import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;

/** Assemble a CSE7000 program with a 2-pass assembler. Create an object file from the source
 * file containing the program.<br>
 * Change Log:<br>
 * 	- 04/08/09 - Tobin Chee<br>
 * 		- Encapsulated tables into classes and moved populateTable() methods into classes.<br>
 * 		- Added enumerations for TokenType and SymbolUsage<br><br>
 * 	- 04/16/09 - Tobin Chee<br>
 * 		- Put all of the enums in this class for consistency. They will all potentially be <br>
 * 		moved to classes later.<br><br>
 * 	- 04/21/09 - Tobin Chee<br>
 * 		- Added new enum ErrorSeverity for use in conjunction with ErrorTable<br><br>
 * 	- 04/27/09 - Tobin Chee<br>
 * 		- Updated various instances of error logging to match changes to the codes in ErrorTable<br>
 * 		- Removed redundant calls to intermediateVersion.updateLocationCounter<br>
 * 		- Added constant integers to the top of ASSEMBLER to be used to validate <br><br>
 *  - 04/27/09 - Meghan Day<br>
 *  	- Filled in documentations of params of all parse operations.<br><br>
 *  - 05/03/09 - Meghan Day<br>
 *  	- Made error messages for parseOperandsEQU more specific.<br><br>
 *  - 05/05/09 - Tobin Chee<br>
 *  	- Added a global variable PRMLSTcount to facilitate parsing PRMID and PRMLST.<br><br>
 *  - 05/09/09 - Tobin Chee<br>
 *  	- Added global variables to track program version and revision number.<br>
 *  	- Added method skeletons for pass two, including putReportToFile(), validateIntermediateVersion(),
 *   putDebugReport(), putObjectFile() and various submethods of the aforementioned methods.<br><br>
 *  - 05/17/09 - Meghan Day<br>
 *  	- Added parse operations for DUMP and PWR.<br><br>
 *  - 05/17/09 - Tobin Chee<br>
 *  	- Filled in the change logs on all methods authored by Tobin Chee.<br>
 *  	- Filled in authors on methods.
 *  
 *  @author Tobin Chee, Meghan Day, Ben Tarney, Dan Carpenter, Sam Jones
 */
public class Assembler {
	// Fixed Tables:
	/** Machine Ops Table. 
	 */
	protected static MachineOpsTable machineOps = new MachineOpsTable();
	
	/** Error Code Table.
	 */
	protected static ErrorTable errors = new ErrorTable();

	/** Assembler Directives Table.
	 */
	protected static DirectivesTable directives = new DirectivesTable();
	
	// Dynamic Tables:
	/** Symbol Table 
	 */
	protected static SymbolTable symbolTable = new SymbolTable();
	
	/** Intermediate Version Table.
	 */
	protected static IntermediateTable intermediateVersion = new IntermediateTable();

	/** Inclusive, ie <= 2^15 - 1. 
	 */
	private static final int MAX_16BIT = (int)Math.pow(2, 15) - 1;

	/** Inclusive, ie <= -(2^15). 
	 */
	private static final int MIN_16BIT = (int)(-Math.pow(2, 15));

	/** Inclusive, ie <= MAX_PROGRAM_LENGTH. 
	 */
	private static final int MAX_PROGRAM_LENGTH = 4095;

	/** Inclusive, ie >= 0. 
	 */
	private static final int MIN_PROGRAM_LENGTH = 0;

	/** Inclusive ie >= -.<br>
	 * Inclusive, ie <= 2^31 - 1. 
	 */
	private static final int MAX_32BIT = (int) (Math.pow(2, 31) - 1);
	
	/** Inclusive, ie <= -(2^31). 
	 */
	private static final int MIN_32BIT = (int) (-Math.pow(2, 31));
	
	/** Max line length.
	 */
	private static final int MAX_LINE_LENGTH = 100;
	/**
	 * After PRMID is parsed, this variable is set to the length of the PRMLST.
	 * When the value of this variable is > 0, the parser will expect the next
	 * memory consuming instruction in the source code to be a PRMLST instruction.
	 * The value is decremented as each valid PRMLST instruction is parsed. If an
	 * expected PRMLST instruction is not found an error is logged, the equValue
	 * corresponding to the PRMID in the symbol table is set to the actual number
	 * of valid PRMLST instructions found, and the value of PRMLSTcount is set to
	 * zero.
	 */
	private static int PRMLSTcount = 0;
	/**
	 * Version # of the program
	 *  - Version 1 was what we turned in for lab1.
	 *  - Version 2 is what will be turned in for lab2.
	 */
	private static final int VERSION_NUMBER = 2;
	/**
	 * Revision # of the program
	 *  - Version 1
	 *  	- Revision 0 - initial setup and coding for pass1.
	 *  	- Revision 1 - parse methods added and coded for pass1.
	 *  	- Revision 2 - Finishing touches for turn in day.
	 *  	- Revision 3 - Major bug fixes based on grader feedback.
	 *  - Version 2
	 *  	- Revision 0 - initial setup and coding for pass2.
	 */
	private static final int REVISION_NUMBER = 0;
	
	/**
	 * Types of tokens that can be parsed.
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Changed blue javadoc comments to green block comments for readability.<br><br>
	 * 	- 05/17/09 - Tobin Chee<br>
	 * 		- Changed block comments back to javadoc comments.
	 */
	public enum TokenType {
		/** MNEMONIC - string starting with an alpha and followed by alpha or digit.
		 */
		MNEMONIC,
		/** DATA - string starting with a digit and followed by a digit or alpha.<br>
		 * 			-this can return an invalid number such as "001PPpx".<br>
		 * 			-conversely it can also return the valid hex number "011FF4".
		 */
		DATA,
		/** IMMEDIATE - "=".
		 */
		IMMEDIATE,
		/** COMMA - ",",
		 */
		COMMA,
		/** WHITESPACE - " ", "(tab)".
		 */
		WHITESPACE,
		/** COMMENT - string beginning with ":" and followed by anything. Reads till end
		 * of sourceLine.
		 */
		COMMENT,
		/** ERROR - any invalid strings. Basically anything but a comment, that contains 
		 * a non-alphanumeric char. 
		 */
		ERROR,
		/** EMPTY - when the tokenizer's internal buffer is empty. A token should never be 
		 * returned with this type.
		 */
		EMPTY,
		/** ARITHMETIC - "+", "-", "*" or "/".
		 */
		ARITHMETIC,
		/** SINGLE_QUOTE - "'".
		 */
		SINGLE_QUOTE,
		/** INDIRECT - "%".
		 */
		INDIRECT;
	}
	
	/** Severity of errors in code.<br><Br>
	 * Change Log:
	 * 	- 05/05/09 - Tobin Chee
	 * 		- Changed blue javadoc comments to green block comments for readability.<br><br>
	 * 	- 05/17/09 - Tobin Chee<br>
	 * 		- Changed block comments back to javadoc comments.
	 */
	public enum ErrorSeverity{
		
		/** FATAL - errors that result in ending assembly and the inability to run the program.<br>
		 * 	-Ex Unexpected end of file.<br>
		 * 	-File does not start with a valid BEGIN statement.
		 */
		FATAL,
		/** SEVERE - errors that allow assembly to continue, but usually result in a NOP replacing the opcode.<br>
		 * 	-Ex. ADD dirtandmudandrain,2, This would be replaced by a NOP and assembly would continue.
		 */
		SEVERE,
		/** WARNING - errors that allow assembly to continue and potentially have little to no effect on the program's function.<br>
		 * 	-Ex. An instruction that does now allow labels, is given a label. The label is ignored and hopefully does not affect the program.<br>
		 * 	-Ex. A label with a comment following directly after.<br>
		 * 	-Ex. A line with no instruction and a label preceded by whitespace.
		 */
		WARNING;
	}
	
	/** 
	 * Enumeration to represent how a symbol is used.
	 * 
	 * Change Log:<br>
	 * 	- 04/21/09 - Tobin Chee<br>
	 * 		- Deleted INSTRUCTION_LABEL from enum because it was unused.<br><br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Changed blue javadoc comments to green block comments for readability.<br><br>
	 * 	- 05/17/09 - Tobin Chee<br>
	 * 		- Changed block comments back to javadoc comments.
	 */
	public enum SymbolUsage {
		/** EQU_VALUE - equated symbol.
		 */
		EQU_VALUE,
		/** PROGRAM_NAME - name of program.
		 */
		PROGRAM_NAME,
		/** DATA_LABEL - label representing location in memory.
		 */
		DATA_LABEL,
		/** PRMID - label for parameter list.
		 */
		PRMID,
		/** EXTRN - external variable.
		 */
		EXTRN,
		/** AVERT - can be used by outside programs.
		 */
		AVERT;
	}

	/** 
	 * Represents the status of the program.
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Changed blue javadoc comments to green block comments for readability.<br><br>
	 * 	- 05/17/09 - Tobin Chee<br>
	 * 		- Changed block comments back to javadoc comments.
	 */
	public enum SourceProgramStatus {
		/** NORMAL - program is in normal compilation.
		 */
		NORMAL,
		/** END_OF_PROGRAM - end of program has been reached.
		 */
		END_OF_PROGRAM,
		/** FATAL_ERROR - a fatal error has been reached and execution is terminated.
		 */
		FATAL_ERROR,
		/** NON_FATAL_ERROR - a non-fatal error has been reached. Its presence will be documented, 
		 * appropriate action will follow and compilation will resume.
		 */
		NON_FATAL_ERROR;
	}

	/** 
	 * Represents whether a label is required, optional, or not allowed.
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Changed blue javadoc comments to green block comments for readability.<br><br>
	 * 	- 05/17/09 - Tobin Chee<br>
	 * 		- Changed block comments back to javadoc comments.
	 */
	public enum LabelAllowed {
		/** REQUIRED - a label is required for this instruction. 
		 */
		REQUIRED,
		/** OPTIONAL - a label is optional for this instruction.
		 */
		OPTIONAL,
		/** NOT_ALLOWED - a label is not permitted for this instruction.
		 */
		NOT_ALLOWED;
	}


	/**
	 * Used at the end of a line after a valid set of commands. This will parse
	 * through the valid tokens such as a line ending with some WHITESPACE and a
	 * NEWLINE, or with a COMMENT, etc... It will also report errors if unexpected
	 * code is found.

	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Updated documentation
	 */
	public static void parseEndOfLine(StringBuffer sourceLine, Tokenizer t, StringBuffer token, TokenType[] type) {
		if (sourceLine.length() > 0) {
			t.getNextToken(sourceLine, token, type);
			
			if (type[0] == TokenType.WHITESPACE) {
				parseEndOfLine(sourceLine, t, token, type);
			} else if (type[0] == TokenType.COMMENT) {
				// do nothing, comments already span to the end of the line
			} else { 
				// If the token is anything else...such as a string of some sort
				// nfe dispense with the rest of the line and log an error
				// DO NOT REPLACE WITH NOP
				intermediateVersion.addError(intermediateVersion.length() - 1, 16);
			}
		}
		else{
			// Do nothing, end of line, no problems
		}
	}

	/** 
	 * Parse the operand field of an instruction.<br><br>
	 * 
	 * Given the operand code of the current instruction, calls the correct parseOperands operation
	 * for that instruction. Also checks to see if the operation and operand field are separated by whitespace<br><br>
	 *  
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @param operandCode Integer representing the operand type of the current instruction.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 04/15/09 - Tobin Chee<br>
	 * 		- Created initial skeleton and began preliminary coding.<br><br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Updated documentation<br><br>
	 * 	- 05/17/09 - Tobin Chee<br>
	 * 		- Put in missing break statements to fix errors.
	 */
	private static void parseOperands(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter, int operandCode){
		
		if(operandCode == 0){
			parseEndOfLine(sourceLine, t, token, type);
		}
		else if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			if(type[0] == TokenType.WHITESPACE){
				switch (operandCode){
					case 1:
						parseOperandsMemRef(t, sourceLine, token, type, locationCounter);
						break;
					case 2:
						parseOperandsNumOrEQU(t, sourceLine, token, type, locationCounter);
						break;
					case 3:
						parseOperandsIOWD2(t, sourceLine, token, type, locationCounter);
						break;
					case 4:
						parseOperandsEXR(t, sourceLine, token, type, locationCounter);
						break;
					case 5:
						parseOperandsCALL(t, sourceLine, token, type, locationCounter);
						break;
					case 7:
						parseOperandsEXTRN(t, sourceLine, token, type, locationCounter);
						break;
					case 8:
						parseOperandsString(t, sourceLine, token, type, locationCounter);
						break;
					case 9:
						parseOperandsPRMID(t, sourceLine, token, type, locationCounter);
						break;
					case 10:
						parseOperandsADRC(t, sourceLine, token, type, locationCounter);
						break;
					case 11:
						parseOperandsBSS(t, sourceLine, token, type, locationCounter);
						break;
					case 12:
						parseOperandsDEC(t, sourceLine, token, type, locationCounter);
						break;
					case 13:
						parseOperandsHEX(t, sourceLine, token, type, locationCounter);
						break;
					case 14:
						parseOperandsOCT(t, sourceLine, token, type, locationCounter);
						break;
					case 15:
						parseOperandsDEBUG(t, sourceLine, token, type, locationCounter);
						break;
					case 16:
						parseOperandsALT(t, sourceLine, token, type, locationCounter);
						break;
					case 17:
						parseOperandsPRMLST(t, sourceLine, token, type, locationCounter);
						break;
					case 18:
						parseOperandsAVERT(t, sourceLine, token, type, locationCounter);
						break;
					case 19:
						parseOperandsDUMP(t, sourceLine, token, type, locationCounter);
						break;
					case 20:
						parseOperandsPWR(t, sourceLine, token, type, locationCounter);
						break;
				}
			}
			else{
				//NFE exp whitespace between operation and operand field
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 23);
			}
		}
		else{
			//nfe unex EOL
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
	}
	
	/** Parse operands for specific instruction ALT.<br>
	 * Extracts the operand for the ALT instruction. 
	 * Does not allow indirection or star notation.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * ChangeLog:<br>
	 * 	- 05/04/09 - Tobin Chee<br>
	 * 		- Method now calls to parseEndOfLine after valid input to catch errors<br><br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Updated documentation<br><br>
	 * 	- 05/17/09 - Tobin Chee<br>
	 * 		- Added error logging for when the tokenizer returns an error token.
	 */
	private static void parseOperandsALT(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter){
		
		if(sourceLine.length() > 0){
			
			t.getNextToken(sourceLine, token, type);
			
			if(type[0] == TokenType.MNEMONIC){
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						int addr = symbolTable.getEQUValue(token.toString());
						
						if((addr >= MIN_PROGRAM_LENGTH) && (addr <= MAX_PROGRAM_LENGTH)){
							
							if(addr >= intermediateVersion.getLocationCounter(0)){ //if address is after the mem addr designated by BEGIN
								intermediateVersion.setProgramStartLocation(addr);
								parseEndOfLine(sourceLine, t, token, type);
							}
							else{ //If address is somewhere betweeen zero and the BEGIN start address
								//nfe ALT start address must be greater than the start address designated by BEGIN
								intermediateVersion.addError(intermediateVersion.length() - 1, 61);
							}
						}
						else{
							//nfe addr value invalid
							intermediateVersion.addError(intermediateVersion.length() - 1, 24);
						}
					}
				}
				else{ //if not defined
					//Symbol symb = new Symbol();
					
					//symb.setLabel(token.toString());
					//symb.setUsage(SymbolUsage.DATA_LABEL);
					//symbolTable.defineSymbol(symb);
					ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
					intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
					parseEndOfLine(sourceLine, t, token, type);
					//Will have to wait till pass two to update the value of the program start value
				}
			}
			else if(type[0] == TokenType.DATA){
				
				try{
					int addr = Integer.parseInt(token.toString());
					
					if((addr >= MIN_PROGRAM_LENGTH) && (addr <= MAX_PROGRAM_LENGTH)){
						
						if(addr >= intermediateVersion.getLocationCounter(0)){ //if address is after the mem addr designated by BEGIN
							intermediateVersion.setProgramStartLocation(addr);
							parseEndOfLine(sourceLine, t, token, type);
						}
						else{ //If address is somewhere betweeen zero and the BEGIN start address
							//nfe ALT start address must be greater than the start address designated by BEGIN
							intermediateVersion.addError(intermediateVersion.length() - 1, 61);
						}
					}
					else{
						//nfe addr value too large
						intermediateVersion.addError(intermediateVersion.length() - 1, 24);
					}
					
				} catch(NumberFormatException nfe){
					//nfe addr value invalid
					intermediateVersion.addError(intermediateVersion.length() - 1, 24);
				}
			}
			else{ //if not a valid operand
				//nfe exp integer or equ value in range of the legal program length
				intermediateVersion.addError(intermediateVersion.length() - 1, 60);
			}
		}
	}
	
	/** 
	 * Parse operands for specific instruction DEBUG directive.<br>
	 * Extracts the operand for the DEBUG directive.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Added missing call to t.getNextToken()
	 */
	private static void parseOperandsDEBUG(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter){
		
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			
			if(type[0] == TokenType.MNEMONIC){
				
				if(token.toString().toUpperCase().compareTo("ON") == 0){
					intermediateVersion.setDebugFlag(true);
					parseEndOfLine(sourceLine, t, token, type);
				}
				else if(token.toString().toUpperCase().compareTo("OFF") == 0){
					intermediateVersion.setDebugFlag(false);
					parseEndOfLine(sourceLine, t, token, type);
				}
				else{
					//nfe exp operand "ON" or "OFF". Non-case sensitive.
					intermediateVersion.addError(intermediateVersion.length() - 1, 25);
				}
			}
			else{
				//nfe exp operand "ON" or "OFF". Non-case sensitive.
				intermediateVersion.addError(intermediateVersion.length() - 1, 25);
			}
		}
		else{
			//nfe unex EOL
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
	}
	
	/** 
	 * Parse operands for the BSS directive.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Updated documentation<br><br>
	 * 	- 05/26/09 - Tobin Chee<br>
	 * 		- Fixed the upper bounds of BSS operand checking so that BSS will accept operands as large as 4096 now.
	 * 		- Updated error message to reflect above change to BSS.
	 */
	private static void parseOperandsBSS(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter){
		
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			
			if(type[0] == TokenType.MNEMONIC){
				
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						
						int addr = symbolTable.getEQUValue(token.toString());
						
						if((addr >= MIN_PROGRAM_LENGTH) && (addr <= (MAX_PROGRAM_LENGTH + 1))){ //upper bounds is max_program_length + 1, because BSS can skip 4096 words legally
							//subtract one because the location counter always auto-increments one for operations that take memory.
							locationCounter[0] = locationCounter[0] + addr - 1;
						}
						else{
							//nfe numeric value out of range (0 <= addr <= 2^15-1)
							
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 62);
						}
					}
					else{
						//nfe exp predefined equ or int decimal value
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 11);
					}
				}
				else{
					//nfe exp predefined equ or int decimal value
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
				}
			}
			else if(type[0] == TokenType.DATA){
				
				try{
					int addr = Integer.parseInt(token.toString());
					
					if((addr >= MIN_PROGRAM_LENGTH) && (addr <= (MAX_PROGRAM_LENGTH + 1))){
						locationCounter[0] = locationCounter[0] + addr - 1;
						//intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
					}
					else{
						//nfe numeric value out of range (0 <= addr <= 2^15-1)
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 62);
					}
				} catch(NumberFormatException nfe){
					//nfe exp predefined equ or int decimal value
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
				}
			}
			else{
				//nfe exp predefined equ or int decimal value
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 11);
			}
		}
		else{
			//nfe unex eol
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
	}
	
	/** 
	 * This is a submethod called by parseOperandsADRC to simplify the task. Parses a potential additional
	 * mathematical operands for instruction ADRC. Only usable for #, data label or equated symbol for first
	 * mathematical operand (not for * notation)
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param exp ArithmeticExpression to which to add additional operands.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Updated documentation<br><br>
	 * 	- 05/07/09 - Tobin Chee<br>
	 * 		- Commented out some unnecessary code.
	 */
	private static void parseAdditionalOperandsADRC(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, ArithmeticExpression exp){
		
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			
			if(type[0] == TokenType.ARITHMETIC){
				ArithmeticExpression.ArithmeticOperator adrcOP;
				if(token.toString().compareTo("+") == 0){
					adrcOP = ArithmeticExpression.ArithmeticOperator.ADD;
				}
				else if(token.toString().compareTo("-") == 0){
					adrcOP = ArithmeticExpression.ArithmeticOperator.SUBTRACT;
				}
				else if(token.toString().compareTo("*") == 0){
					adrcOP = ArithmeticExpression.ArithmeticOperator.MULTIPLY;
				}
				else{ //if(token.toString().compareTo("/") == 0)
					adrcOP = ArithmeticExpression.ArithmeticOperator.DIVIDE;
				}
				
				if(sourceLine.length() > 0){
					t.getNextToken(sourceLine, token, type);
					
					if(type[0] == TokenType.MNEMONIC){
						
						if(symbolTable.symbolIsDefined(token.toString())){
							
							if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
								exp.defineTermOperandPair(symbolTable.getEQUValue(token.toString()), ArithmeticExpression.Sign.POSITIVE, adrcOP);
								parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
							}
							else{ //if usage is data_label
								exp.defineLabelOperandPair(token.toString(), ArithmeticExpression.Sign.POSITIVE, adrcOP);
								parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
							}
						}
						else{
							//Symbol symb = new Symbol();
							
							//symb.setLabel(token.toString());
							//symb.setUsage(SymbolUsage.DATA_LABEL);
							//symbolTable.defineSymbol(symb);
							exp.defineLabelOperandPair(token.toString(), ArithmeticExpression.Sign.POSITIVE, adrcOP);
							parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
						}
					}
					else if(type[0] == TokenType.DATA){
						try{
							int x = Integer.parseInt(token.toString());
							
							exp.defineTermOperandPair(x, ArithmeticExpression.Sign.POSITIVE, adrcOP);
							parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
						} catch(NumberFormatException nfe){
							//nfe severe, invalid numeric operand, must be base ten
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 11);
						}
					}
					else{
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 8);
					}
				}
				else{
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 1);
				}
			}
			else {
				
				if(exp.length() <= 4){
					if(exp.containsLabels()){
						intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
					}
					else{
						intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, exp.evaluate());
					}
					sourceLine.append(token);
					parseEndOfLine(sourceLine, t, token, type);
				}
				else{
					//nfe to many operands in expression
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 28);
				}
			}
		}
		else{
			//valid EOL, evaluate and update addr field
			if(exp.length() <= 4){
				if(exp.containsLabels()){
					intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
				}
				else{
					intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, exp.evaluate());
				}
				parseEndOfLine(sourceLine, t, token, type);
			}
			else{
				//nfe to many operands in expression
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 28);
			}
		}
	}
	
	/**
	 * Parses the operand field for the operation ADRC. Sets the addr_flag based on the operands given. The XR_flag defaults to 0 because index
	 * registers are not valid operands for this instruction. For valid instructions, all data_labels are stored to have their values determined 
	 * by the symbol_table in pass2. All other numeric and equated values are evaluated on the spot and placed in the operand field. After valid 
	 * operands are found, this method calls through to parseEndOfLine() to deal with any whitespace, comments or extra code on the end of the 
	 * line. When errors are found, they are logged in the intermediate version and the opCode is replaced with a NOP.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Updated documentation<br><br>
	 * 	- 05/07/09 - Tobin Chee<br>
	 * 		- Commented out some unnecessary code.
	 */
	private static void parseOperandsADRC(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter){
		
		if(sourceLine.length() > 0){
			ArithmeticExpression exp;
			
			t.getNextToken(sourceLine, token, type);
			
			if(type[0] == TokenType.MNEMONIC){
				
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						exp = new ArithmeticExpression(symbolTable.getEQUValue(token.toString()), ArithmeticExpression.Sign.POSITIVE);
						parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
					}
					else{ //if usage is data_label
						exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
						parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
					}
				}
				else{
					//Symbol symb = new Symbol();
					
					//symb.setLabel(token.toString());
					//symb.setUsage(SymbolUsage.DATA_LABEL);
					//symbolTable.defineSymbol(symb);
					
					exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
					parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
				}
			}
			else if(type[0] == TokenType.DATA){
				
				try{
					int x = Integer.parseInt(token.toString());
					
					exp = new ArithmeticExpression(x, ArithmeticExpression.Sign.POSITIVE);
					parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
				} catch(NumberFormatException nfe){
					//nfe, severe exp valid integer value
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
				}
			}
			else if(type[0] == TokenType.ARITHMETIC){
				
				if(token.toString().compareTo("*") == 0){
					exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
					exp.updateTermValue(exp.length() - 1, locationCounter[0]);
					parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
				}
				else if((token.toString().compareTo("+") == 0) ||
						(token.toString().compareTo("-") == 0)){
					ArithmeticExpression.Sign adrcSign = ArithmeticExpression.Sign.NEGATIVE;
					if(token.toString().compareTo("+") == 0){
						adrcSign = ArithmeticExpression.Sign.POSITIVE;
					}
					else if(token.toString().compareTo("-") == 0){
						adrcSign = ArithmeticExpression.Sign.NEGATIVE;
					}
					
					if(sourceLine.length() > 0){
						t.getNextToken(sourceLine, token, type);
						
						if(type[0] == TokenType.MNEMONIC){
							
								if(symbolTable.symbolIsDefined(token.toString())){
									
									if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
										exp = new ArithmeticExpression(symbolTable.getEQUValue(token.toString()), adrcSign);
										parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
									}
									else{
										exp = new ArithmeticExpression(token.toString(), adrcSign);
										parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
									}
								}
								else{
									//Symbol symb = new Symbol();
									
									//symb.setLabel(token.toString());
									//symb.setUsage(SymbolUsage.DATA_LABEL);
									//symbolTable.defineSymbol(symb);
									
									exp = new ArithmeticExpression(token.toString(), adrcSign);
									parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
								}
						}
						else if(type[0] == TokenType.DATA){
							
							try{
								int x = Integer.parseInt(token.toString());
								
								exp = new ArithmeticExpression(x, adrcSign);
								parseAdditionalOperandsADRC(t, sourceLine, token, type, exp);
							} catch(NumberFormatException nfe){
								//nfe, severe exp valid integer value
								
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length() - 1, 11);
							}
						}
						else{
							//nfe error expecting symbol name or integer (after sign character)
							
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 8);
						}
					}
				}
				else{ //if "/"
					//nfe exp mem token (label, #, sign or * notation) as first token					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 9);
				}
			}
			else if(type[0] == TokenType.INDIRECT){
				intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 1);
				
				if(sourceLine.length() > 0){
					t.getNextToken(sourceLine, token, type);
					
					if(type[0] == TokenType.MNEMONIC){
						
						if(symbolTable.symbolIsDefined(token.toString())){
							
							if(symbolTable.getUsage(token.toString()) == Assembler.SymbolUsage.EQU_VALUE){
								int addr = symbolTable.getEQUValue(token.toString());

								if((addr >= MIN_16BIT) && (addr <= MAX_16BIT)){
									intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, addr);
								}
								else{
									//NFE exp valid Integer mem address x, such that (-2^15 <= addr <= 2^15 - 1)
									
									intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
									intermediateVersion.addError(intermediateVersion.length() - 1, 13);
								}
							}
							else{ //if symbol is a data label
								exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
								intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
							}
						}
						else{
							//Symbol symb = new Symbol();
							//symb.setLabel(token.toString());
							//symb.setUsage(SymbolUsage.DATA_LABEL);
							exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
							intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
						}
					} 
					else if(type[0] == TokenType.DATA){
			
						try{
							int addr = Integer.parseInt(token.toString());
							
							if((addr >= MIN_16BIT) && (addr <= MAX_16BIT)){
								intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, addr);
							}
							else{
								//NFE exp valid Integer mem address x, such that x is a valid 16 bit two's comp integer
								
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length() - 1, 13);
							}
						} catch(NumberFormatException nfe){
							// NFE exp symbol or valid decimal int
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 11);
						}
					}
					else{
						//nfe exp symbol or int
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 8);
					}
				}
				else{
					//nfe unex EOL
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 1);
				}
			}
			else{
				//nfe exp mem token (label, #, sign, % or * notation) as first token
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 9);
			}
		}
		else{
			//nfe unex eol
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
		
	}

	/** 
	 * Parses the operand field for the EQU directive and returns the result as a string. When invalid operands
	 * are encountered, this method logs errors in the intermediate table and returns the value "Fail!". This
	 * method is called by the parseLabel method to simplify parsing the EQU directive. 
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @return The string representation of the integer operand.  Returns "Fail!" if an error is encountered.
	 * @author Meghan Day
	 * 
	 * Change Log:<br>
	 *  - 04/22/09 - Meghan Day<br>
	 *  	- Changed return type and filled in method<br><br>
	 *  - 04/24/09 - Meghan Day<br>
	 *  	- Fixed some errors and cleaned up the code slightly<br><br>
	 *  - 04/25/09 - Meghan Day<br>
	 *  	- Fixed more errors<br><br>
	 *  - 04/26/09 - Meghan Day<br>
	 *  	- Filled in remaining error messages.<br><br>
	 *  - 05/03/09 - Meghan Day<br>
	 *  	- Made error messages more specific.<br><br>
	 *  - 05/05/09 - Tobin Chee<br>
	 *  	- Updated documentation (added author javadoc and edited description)<br><br>
	 *  - 05/11/09 - Meghan Day<br>
	 *  	- Fixed some error reporting to be more accurate.
	 */
	private static String parseOperandsEQU(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter){
		
		if(sourceLine.length() > 0){
			
			String evaluatedExpression;
			ArithmeticExpression expression = new ArithmeticExpression(0, ArithmeticExpression.Sign.POSITIVE);  // default value, should be changed
			
			t.getNextToken(sourceLine, token, type);
			
			// if first token is *
			if (token.toString().compareTo("*") == 0){
				ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
				exp.updateTermValue(exp.length() - 1, locationCounter[0]);
			}
			// if first token is + or - (or /, in which case error)
			else if (type[0] == TokenType.ARITHMETIC) {
				String sign = token.toString();
				if (sign.compareTo("/") == 0) {
					intermediateVersion.addError(intermediateVersion.length() - 1, 91);
					// started with / instead of + or -
					return "Fail!";
				}
				
				else if (sourceLine.length() > 0) {
					t.getNextToken(sourceLine, token, type);
					
					// if token following sign is a number
					if (type[0] == TokenType.DATA) {
						try {
							int initialValue = Integer.parseInt(token.toString());

							if (sign.compareTo("+") == 0) {
								expression = new ArithmeticExpression(initialValue, ArithmeticExpression.Sign.POSITIVE);
							}
							
							else if (sign.compareTo("-") == 0) {
								expression = new ArithmeticExpression(initialValue, ArithmeticExpression.Sign.NEGATIVE);
							}
							
							else {
								intermediateVersion.addError(intermediateVersion.length() - 1, 91);
								// started with / instead of + or -
								return "Fail!";
							}
						}
						catch (NumberFormatException nfe) {
							// expecting number or equated symbol, contained something like
							// ALS +2bed
							intermediateVersion.addError(intermediateVersion.length() - 1, 11);
							return "Fail!";
						}
					}
					
					// if token following sign is a symbol
					else if (type[0] == TokenType.MNEMONIC) {
						if (symbolTable.symbolIsDefined(token.toString())) {
							
							if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
								int initialValue = symbolTable.getEQUValue(token.toString());
								
								if (sign.compareTo("+") == 0) {
									expression = new ArithmeticExpression(initialValue, ArithmeticExpression.Sign.POSITIVE);
								}
								else if (sign.compareTo("-") == 0) {
									expression = new ArithmeticExpression(initialValue, ArithmeticExpression.Sign.NEGATIVE);
								}
								else {
									intermediateVersion.addError(intermediateVersion.length() - 1, 91);
									// started with / instead of + or -
									return "Fail!";
								}
							}
							else {
								// symbol defined but not equated
								intermediateVersion.addError(intermediateVersion.length() - 1, 92);
								return "Fail!";
							}
							
						}
						else {
							// symbol not defined
							intermediateVersion.addError(intermediateVersion.length() - 1, 17);
							return "Fail!";
						}
					}
					else {
						// + or - followed by something that's not a number or symbol
						intermediateVersion.addError(intermediateVersion.length() - 1, 11);
						return "Fail!";
					}
				}
				else {
					// + or - followed by nothing
					intermediateVersion.addError(intermediateVersion.length() - 1, 93);
					return "Fail!";
				}
			}
			// if first token is a number
			else if (type[0] == TokenType.DATA) {
				try {
					int initialValue = Integer.parseInt(token.toString());
					expression = new ArithmeticExpression(initialValue, ArithmeticExpression.Sign.POSITIVE);
				}
				catch (NumberFormatException nfe) {
					// expecting # or equ symb
					// is something like ALS 3ab
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
					return "Fail!";
				}
			}
			// if first token is a symbol
			else if (type[0] == TokenType.MNEMONIC) {
				if (symbolTable.symbolIsDefined(token.toString())) {
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						int initialValue = symbolTable.getEQUValue(token.toString());
						expression = new ArithmeticExpression(initialValue, ArithmeticExpression.Sign.POSITIVE);
					}
					else {
						// symbol defined but not equated
						intermediateVersion.addError(intermediateVersion.length() - 1, 92);
						return "Fail!";
					}
				}
				else {
					// symbol not defined
					intermediateVersion.addError(intermediateVersion.length() - 1, 17);
					return "Fail!";
				}
			}
			
			else if (token.charAt(0) == ':') {
				// comment, missing operand
				intermediateVersion.addError(intermediateVersion.length() - 1, 94);
				return "Fail!";
			}
			else {
				// token is not *,+,-,/, :, a number, or a symbol
				intermediateVersion.addError(intermediateVersion.length() - 1, 11);
				return "Fail!";
			}
			
			// begin iteration for remaining up to three operands
			if (sourceLine.length() > 0) {
				t.getNextToken(sourceLine, token, type);

				int count = 3;	// To keep track of the number of operands, limit of four
				while ((type[0] == TokenType.ARITHMETIC) && (count > 0) && (sourceLine.length() > 0)) {
					String operator = token.toString();
					int value = 0;
					if (sourceLine.length() > 0) {
						t.getNextToken(sourceLine, token, type);
						
						// put operand into value
						if (type[0] == TokenType.DATA) {
							try {
								value = Integer.parseInt(token.toString());
							}
							catch (NumberFormatException nfe) {
								// expecting # or equ symb
								intermediateVersion.addError(intermediateVersion.length() - 1, 11);
								return "Fail!";
							}
						}
						else if (type[0] == TokenType.MNEMONIC) {
							if (symbolTable.symbolIsDefined(token.toString())) {
								if (symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE) {
									value = symbolTable.getEQUValue(token.toString());
								}
								else {
									// symbol defined but not equated
									intermediateVersion.addError(intermediateVersion.length() - 1, 92);
									return "Fail!";
								}
							}
							else {
								// symbol not defined
								intermediateVersion.addError(intermediateVersion.length() - 1, 17);
								return "Fail!";
							}
						}
						else {
							// ALS 9+something that is not a number or equated symbol
							intermediateVersion.addError(intermediateVersion.length() - 1, 95);
							return "Fail!";
						}
						
						if (operator.compareTo("+") == 0) {
							expression.defineTermOperandPair(value, ArithmeticExpression.Sign.POSITIVE, ArithmeticExpression.ArithmeticOperator.ADD);
						}
						else if (operator.compareTo("-") == 0) {
							expression.defineTermOperandPair(value, ArithmeticExpression.Sign.POSITIVE, ArithmeticExpression.ArithmeticOperator.SUBTRACT);
						}
						else if (operator.compareTo("*") == 0) {
							expression.defineTermOperandPair(value, ArithmeticExpression.Sign.POSITIVE, ArithmeticExpression.ArithmeticOperator.MULTIPLY);
						}
						else if (operator.compareTo("/") == 0) {
							expression.defineTermOperandPair(value, ArithmeticExpression.Sign.POSITIVE, ArithmeticExpression.ArithmeticOperator.DIVIDE);
						}
						count--;
						if (sourceLine.length() > 0) {
							t.getNextToken(sourceLine, token, type);
						}
					}
					else {
						intermediateVersion.addError(intermediateVersion.length() - 1, 95);
						return "Fail!";
					}
				}
				
			}
			
			evaluatedExpression = new String(String.valueOf(expression.evaluate()));
			parseEndOfLine(sourceLine, t, token, type);
			return evaluatedExpression;
			
		}
		else {
			// no operands, passed empty string
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
			return "Fail!";
		}
	}
	
	/** 
	 * Parse operand field where memory reference is allowed, such as instructions like ADD, SUB, etc...
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Ben Tarney
	 * 
	 * Change Log:<br>
	 * 	- 04/19/09 - Ben Tarney<br>
	 * 		- Created intital outine and began filling in<br><br>
	 * - 04/20/09 - Ben Tarney<br>
	 * 		- Determined if/else flow of method and filled in mnemonic and immediate<br><br>
	 * - 04/21/09 - Ben Tarney<br>
	 * 		- filled in rest of method<br><br>
	 * - 04/22/09 - Ben Tarney<br>
	 * 		- updated some issues with immediate <br><br>
	 * - 04/24/09 - Ben Tarney<br>
	 * 		- added the abilty to do * addressing. missing prior to this<br><br>
	 * - 04/24/09 - Ben Tarney<br>
	 * 		- added index registers to * addressing<br><br>
	 * - 04/25/09 - Ben Tarney<br>
	 * 		- added error codes<br><br>
	 * - 04/26/09 - Ben Tarney<br>
	 * 		- fixed bugs and updated error codes<br><br>
	 * - 04/27/09 - Ben Tarney<br>
	 * 		- added equated values to star notation updated more error codes<br><br>
	 * - 05/05/09 - Ben Tarney<br>
	 * 		- Updated change log<br><br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Updated documentation<br><br>
	 * 	- 05/17/09 - Tobin Chee<br>
	 * 		- Updated code to properly relocate for star notation
	 * 
	 */
	private static void parseOperandsMemRef(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter) {
		
		if (sourceLine.length() > 0) {
			t.getNextToken(sourceLine, token, type);
			if (type[0] == TokenType.MNEMONIC) { // memory reference is either an equated symbol or label
					intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 0); // set address flag to relative
					parseMnemonic(t, sourceLine, token, type, locationCounter); // parse the mnemonic
			} 
			else if (type[0] == TokenType.IMMEDIATE) { // memory reference
					// contains an immediate value
					intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 2);// set address flag to immediate
				
					if (sourceLine.length() > 0) {
					t.getNextToken(sourceLine, token, type);
						if (type[0] == TokenType.DATA) { // data should follow the = in an immediate
							try{
								int addr = Integer.parseInt(token.toString());
								if( addr > MAX_16BIT  || addr < MIN_16BIT){
									intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
									// data too large/small
									intermediateVersion.addError(intermediateVersion.length()-1, 13);
								}
								else{
								intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);// take immediate data and place it in address field
								parseEndOfLine(sourceLine, t, token, type); // after data should be end of line of code
								}
							} catch (NumberFormatException nfe) {
								//nfe exp string in single quotes or integer value
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length()-1, 46);
							}
						}
						else if (type[0] == TokenType.SINGLE_QUOTE) { // ascii string can follow immediate
							if (sourceLine.length() > 0) {
								t.getNextToken(sourceLine, token, type);
								StringBuffer temp = new StringBuffer();
								int addr = 0; //addr of string
								Boolean endOfLine = false;
								while((type[0] != TokenType.SINGLE_QUOTE) && (!endOfLine)){
										temp.append(token);
										
										if(sourceLine.length() > 0){
											t.getNextToken(sourceLine, token, type);
										}
										else{
											// unexpected end of line
											intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
											intermediateVersion.addError(intermediateVersion.length()-1, 1);
											endOfLine = true;
										}
								}
								if(temp.length() <= 2){
									while(temp.length() < 2){
										temp.append(' ');
									}
									while(temp.length() > 0){
										int ch = (int)temp.charAt(0);
										temp.deleteCharAt(0);
										addr = addr * 256 + ch;
									}
									if(addr <= MAX_16BIT  && addr >= MIN_16BIT){
										intermediateVersion.updateAddr(intermediateVersion.length()-1, addr);
										parseEndOfLine(sourceLine, t, token, type);
									}
									else{
										intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
										// too large/small value
										intermediateVersion.addError(intermediateVersion.length()-1, 13);
									}
								}
								else{
									// NFE string too large
									
									intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
									intermediateVersion.addError(intermediateVersion.length() - 1, 71);

								}
								

					
					
							}
							else {// unexpected end of line
								
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length()-1, 1);
							}
					
						}
						else{
							//unexpected
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length()-1, 46);
							
						}
						
					}
					else{
						// unexpected end of line
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length()-1, 1);
					}
			}
			else if (type[0] == TokenType.INDIRECT) { // memory reference is indirect

					intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 1);// set address flag to indirect

					if (sourceLine.length() > 0) {
						t.getNextToken(sourceLine, token, type);
	
						if (type[0] == TokenType.DATA) { // if data follows %
							parseMemData(t, sourceLine, token, type, locationCounter);// parse the data
						} 
						else if (type[0] == TokenType.MNEMONIC) { // if label follows %
							parseMnemonic(t, sourceLine, token, type, locationCounter); // parse the mnemonic
						} 
						else { // NFE expected data or mnemonic
							
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 32);

						}
					}
					else{
						// unexpected end of line
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length()-1, 1);
					}

			} 
			else if (type[0] == TokenType.DATA) { // memory reference is direct value

				intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 0);// set address flag to relative
				parseMemData(t, sourceLine, token, type, locationCounter);// parse the data
			} 
			else if (type[0] == TokenType.ARITHMETIC) {// star notation
				if(token.charAt(0) == '*'){// should be a star
					int addr = locationCounter[0];
					ArithmeticExpression exp = new ArithmeticExpression(token.toString(),ArithmeticExpression.Sign.POSITIVE);
					
					exp.updateTermValue(exp.length() - 1, locationCounter[0]);			
					intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 0); // set address flag to relative
					
					if(sourceLine.length() > 0){
						t.getNextToken(sourceLine, token, type);
						if(type[0] == TokenType.ARITHMETIC){
							if(token.charAt(0) == '+'){
								if(sourceLine.length() > 0 ){
									t.getNextToken(sourceLine, token, type);
									if(type[0] == TokenType.DATA){
										
										try{
											addr = Integer.parseInt(token.toString());
											exp.defineTermOperandPair(addr, ArithmeticExpression.Sign.POSITIVE, ArithmeticExpression.ArithmeticOperator.ADD);
											intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
											
											if(sourceLine.length() > 0){
												t.getNextToken(sourceLine, token, type);
												if(type[0] == TokenType.COMMA){
													parseIndexReg(t, sourceLine, token, type, locationCounter);
												}
												else{
													sourceLine.insert(0, token); //put token back in so parseEndOfLine can check if the token is erroneous
													parseEndOfLine(sourceLine, t, token, type);
												}
												/*
												 * TODO make sure this is correctly commented out
												else if(type[0] == TokenType.WHITESPACE || type[0] == TokenType.COMMENT){// end of line
													parseEndOfLine(sourceLine, t, token, type); // after data should be end of line of code
												}
												else{
													intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
													intermediateVersion.addError(intermediateVersion.length() - 1, 16);
												}
												*/
											}
											else{
												//Do nothing, expected valid eol
											}
										} catch (NumberFormatException nfe){
											//TODO nfe invalid data exp addition or subtraction from star to be a valid 32-bit int
											intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
											intermediateVersion.addError(intermediateVersion.length()-1, 59);
										}
									}
									else if(type[0] == TokenType.MNEMONIC){// equ value
										//TODO tag this method needs a serious rework to function properly
										if(symbolTable.symbolIsDefined(token.toString()) == true){
											
											if(symbolTable.getUsage(token.toString()) == Assembler.SymbolUsage.EQU_VALUE){ //equated value put in intermediate version
												addr = symbolTable.getEQUValue(token.toString());
												exp.defineTermOperandPair(addr, ArithmeticExpression.Sign.POSITIVE, ArithmeticExpression.ArithmeticOperator.ADD);
												intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
												
												/*
												 * unnecesary, EQU values are always in range
												if(symbolTable.getEQUValue(token.toString()) > MAX_16BIT || symbolTable.getEQUValue(token.toString()) < MIN_16BIT){// invaid address
													intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
													intermediateVersion.addError(intermediateVersion.length()-1, 13);
												}
												else{// valid address
													intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr + symbolTable.getEQUValue(token.toString()));
												}
												*/
											}
										
											else{
												//error must be equ value
												intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
												intermediateVersion.addError(intermediateVersion.length()-1, 11);
											}
										}
										else{// error sym not definined
											intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
											intermediateVersion.addError(intermediateVersion.length()-1, 11);
											
										}
										
										if(sourceLine.length() > 0){
											t.getNextToken(sourceLine, token, type);
											if(type[0] == TokenType.COMMA){
												parseIndexReg(t, sourceLine, token, type, locationCounter);
											}
											else if(type[0] == TokenType.WHITESPACE || type[0] == TokenType.COMMENT){// end of line
												parseEndOfLine(sourceLine, t, token, type); // after data should be end of line of code
											}
											else{
												//error unexpected
												
												intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
												intermediateVersion.addError(intermediateVersion.length() - 1, 16);

											}
											
										}
										
									}
									else{
										// error data expected
										
										intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
										intermediateVersion.addError(intermediateVersion.length() - 1, 11);
									}

								}
								else{// unexpected end of line
									// unexpected end of line
									
									intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
									intermediateVersion.addError(intermediateVersion.length()-1, 1);
									}
							}
							else if(token.charAt(0) == '-'){
								if(sourceLine.length() > 0 ){
									t.getNextToken(sourceLine, token, type);
									if(type[0] == TokenType.DATA){
										addr = addr - Integer.parseInt(token.toString());
										if(addr > MAX_16BIT || addr < MIN_16BIT){
											intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
											intermediateVersion.addError(intermediateVersion.length()-1, 13);
										}
										else{
										intermediateVersion.updateAddr(intermediateVersion.length() -1, addr);
										}
										if(sourceLine.length() > 0){
											t.getNextToken(sourceLine, token, type);
											if(type[0] == TokenType.COMMA){
												parseIndexReg(t, sourceLine, token, type, locationCounter);
											}
											else if(type[0] == TokenType.WHITESPACE || type[0] == TokenType.COMMENT){// end of line
												parseEndOfLine(sourceLine, t, token, type); // after data should be end of line of code
											}
											else{
												//error unexpected
												
												intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
												intermediateVersion.addError(intermediateVersion.length() - 1, 16);

											}
											
										}
										else{
											// no index register
											if(addr > MAX_16BIT || addr < MIN_16BIT){
												intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
												intermediateVersion.addError(intermediateVersion.length()-1, 13);
											}
											else{
											intermediateVersion.updateAddr(intermediateVersion.length() -1, addr);
											parseEndOfLine(sourceLine, t, token, type); // after data should be end of line of code
											}
										}
										
									}
									else if(type[0] == TokenType.MNEMONIC){
										if(symbolTable.symbolIsDefined(token.toString()) == true){
											if(symbolTable.getUsage(token.toString()) == Assembler.SymbolUsage.EQU_VALUE){ //equated value put in intermediate version
												if(symbolTable.getEQUValue(token.toString()) > MAX_16BIT || symbolTable.getEQUValue(token.toString()) < MIN_16BIT){// invaid address
													intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
													intermediateVersion.addError(intermediateVersion.length()-1, 13);
												}
												else{// valid address
													intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr - symbolTable.getEQUValue(token.toString()));
												}
											}
										
											else{
												//error must be equ value
												intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
												intermediateVersion.addError(intermediateVersion.length()-1, 22);
											}
										}
										else{
											intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
											intermediateVersion.addError(intermediateVersion.length()-1, 11);
										}
										if(sourceLine.length() > 0){
											t.getNextToken(sourceLine, token, type);
											if(type[0] == TokenType.COMMA){
												parseIndexReg(t, sourceLine, token, type, locationCounter);
											}
											else if(type[0] == TokenType.WHITESPACE || type[0] == TokenType.COMMENT){// end of line
												parseEndOfLine(sourceLine, t, token, type); // after data should be end of line of code
											}
											else{
												//error unexpected
												
												intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
												intermediateVersion.addError(intermediateVersion.length() - 1, 16);
											}
											
										}
									}
									else{
										// error data expected
										
										intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
										intermediateVersion.addError(intermediateVersion.length() - 1, 11);
									}

								}
								else{// unexpected end of line
									// unexpected end of line
									
									intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
									intermediateVersion.addError(intermediateVersion.length()-1, 1);
									}
							}
							else{//error + or - only
								
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length() - 1, 6);
								
							}
							
						}
						else if(type[0] == TokenType.COMMA){// * then index
							if( addr > MAX_16BIT || addr < MIN_16BIT){
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length()-1, 13);
							}
							else{
							intermediateVersion.updateAddr(intermediateVersion.length()-1, addr);
							}
							parseIndexReg(t, sourceLine, token, type, locationCounter);
							}
						else{
							//error
						}
					}
					else{ // contains * only
						intermediateVersion.updateAddr(intermediateVersion.length()-1, addr);
						parseEndOfLine(sourceLine, t, token, type); // after data should be end of line of code
					}
				}
				else{
					// * expected
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 72);

				}
			}
				
				
			else { // NFE unexpected operand
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 16);

			}
		}
		else{
			// unexpected end of line
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length()-1, 1);
		}
	}
	
	/**Parses all index register requests for use in the parseOperandsMemRef.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Ben Tarney
	 * 
	 * Change Log:<br>
	 * 	- 04/26/09 - Ben Tarney<br>
	 * 		- Created method and filled in<br><br>
	 * - 04/27/09 - Ben Tarney<br>
	 * 		- Updated error codes<br><br>
	 * - 05/05/09 - Ben Tarney<br>
	 * 		- Updated change log
	 */
	private static void parseIndexReg(Tokenizer t, StringBuffer sourceLine,StringBuffer token, TokenType[] type, int[] locationCounter) {
		if (sourceLine.length() > 0) { // check next token
			t.getNextToken(sourceLine, token, type);
		
			if (type[0] == TokenType.DATA) { // should be data

				if (Integer.parseInt(token.toString()) >= 1 && Integer.parseInt(token.toString()) <= 7) { // index register needs to be between 1-7
					intermediateVersion.updateIndexRegister(intermediateVersion.length() - 1, Integer.parseInt(token.toString()));// put the index register into intermediateVersion
					parseEndOfLine(sourceLine, t, token, type); // after data should be end of line of code
				}
				else { // NFE expected register value 1-7
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 10);


				}
			}
			else if(type[0] == TokenType.MNEMONIC){// equ value
				if(symbolTable.symbolIsDefined(token.toString()) == true){
					if(symbolTable.getUsage(token.toString()) == Assembler.SymbolUsage.EQU_VALUE){
						int indexReg = symbolTable.getEQUValue(token.toString());
						if( indexReg >=1 && indexReg <= 7){
							intermediateVersion.updateIndexRegister(intermediateVersion.length() - 1, indexReg);// put the index register into intermediateVersion
							parseEndOfLine(sourceLine, t, token, type); // after data should be end of line of code
						}
						else{
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 10);
						}
					}
					else{
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 33);
					}
				}
				else{
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 17);
				}
				
			}
			else { // NFE expected data or equated value
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 11);
			}
		}
		else{
			//NFE unexpected end of line
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length()-1, 1);
		}
	}

	/**Parses all mnemonic types of operands for use in the parseOperandsMemef.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Ben Tarney
	 * 
	 * 
	 * Change Log:<br>
	 * - 04/24/09 - Ben Tarney<br>
	 * 		- Created mehod and began filling in<br><br>
	 * - 04/25/09 - Ben Tarney<br>
	 * 		- Finished method<br><br>
	 * - 04/26/09 - Ben Tarney<br>
	 * 		- added and updated error codes<br><br>
	 * - 04/26/09 - Ben Tarney<br>
	 * 		- fixed some bugs<br><br>
	 * - 04/27/09 - Ben Tarney<br>
	 * 		- updated error codes changes how index registers are parsed<br><br>
	 * - 05/05/09 - Ben Tarney<br>
	 * 		- Updated change log<br>
	 *		- removed try/catch because it was no longer used<br>
	 *		- updated error codes
	 */
	private static void parseMnemonic(Tokenizer t, StringBuffer sourceLine,StringBuffer token, TokenType[] type, int[] locationCounter) {
		if (symbolTable.symbolIsDefined(token.toString()) == true) { // check to see if in symbol table
				if(symbolTable.getUsage(token.toString()) == Assembler.SymbolUsage.EQU_VALUE){ //equated value put in intermediate version
					if(symbolTable.getEQUValue(token.toString()) > MAX_16BIT || symbolTable.getEQUValue(token.toString()) < MIN_16BIT){// invaid address
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length()-1, 13);
					}
					else{// valid address
					intermediateVersion.updateAddr(intermediateVersion.length() - 1, symbolTable.getEQUValue(token.toString()));
					}
				}
				else{ //if symbol is a data label
					ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
					intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
				}
				if (sourceLine.length() > 0) {
					t.getNextToken(sourceLine, token, type);
				
				
					if (type[0] == TokenType.COMMA) { // see if there is a index register
						parseIndexReg(t, sourceLine, token, type, locationCounter);
					}
					else if (type[0] == TokenType.WHITESPACE || type[0] == TokenType.COMMENT) { // if no comma for index register should be nothing end of line
						parseEndOfLine(sourceLine, t, token, type); // end of line of code
					}
					else { // NFE expected comma or end of line
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 16);

					}
				}
			else{// source line is zero end of line
				parseEndOfLine(sourceLine, t, token, type); // end of line of code
			}
		}
		else { // if not in table add too table
			//Symbol symb = new Symbol();
			//symb.setLabel(token.toString());
			//symb.setUsage(SymbolUsage.DATA_LABEL);
			//symbolTable.defineSymbol(symb);
			ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE); //tag
			intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
			if (sourceLine.length() > 0) {
				t.getNextToken(sourceLine, token, type);
			
			
				if (type[0] == TokenType.COMMA) { // see if there is a index register
					parseIndexReg(t, sourceLine, token, type, locationCounter);
				}
				else if (type[0] == TokenType.WHITESPACE || type[0] == TokenType.COMMENT) { // if no comma for index register should be nothing end of line
					parseEndOfLine(sourceLine, t, token, type); // end of line of code
				}
				else { // NFE expected comma or end of line
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 16);

				}
			}
			else{ // source line equals zero end of line
				parseEndOfLine(sourceLine, t, token, type); // end of line of code
			}
			
		}
	}

	/** Parse fields for operand fields of type data which are addresses not
	 * registers or an immediate.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Ben Tarney
	 * 
	 * 	 * Change Log:<br>
	 * - 04/24/09 - Ben Tarney<br>
	 * 		- Created mehod and began filling in<br><br>
	 * - 04/25/09 - Ben Tarney<br>
	 * 		- Finished method<br><br>
	 * - 04/26/09 - Ben Tarney<br>
	 * 		- added error codes<br><br>
	 * - 04/26/09 - Ben Tarney<br>
	 * 		- updated error codes and fixed bugs<br><br>
	 * - 04/27/09 - Ben Tarney<br>
	 * 		- updated how index registers are parsed now calls method<br><br>
	 * - 05/05/09 - Ben Tarney<br>
	 * 		- Updated change log<br>
	 * 		- updated error codes
	 */
	private static void parseMemData(Tokenizer t, StringBuffer sourceLine,StringBuffer token, TokenType[] type, int[] locationCounter) {
	try{	
		if(Integer.parseInt(token.toString()) > MAX_16BIT || Integer.parseInt(token.toString()) < MIN_16BIT){// invalid address
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length()-1, 13);
		}
		else{ // valid address
		intermediateVersion.updateAddr(intermediateVersion.length()-1, Integer.parseInt(token.toString()));//local address place in intermediate version
		}
		if (sourceLine.length() > 0) { // check next token
			t.getNextToken(sourceLine, token, type);
		
			if (type[0] == TokenType.COMMA) { // see if there is a index register
				parseIndexReg(t, sourceLine, token, type, locationCounter);
			} 
			else if (type[0] == TokenType.WHITESPACE
				|| type[0] == TokenType.COMMENT) { // if no comma for index register should be nothing end of line
					parseEndOfLine(sourceLine, t, token, type); // end of line of code
			} 
			else { // NFE expected comma or end of line
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length()-1, 16);

			}
		}
		else{//end of line just data no comma
			parseEndOfLine(sourceLine, t, token, type); // end of line of code
		}
	}	
		
	catch (NumberFormatException nfe) {
        intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
		intermediateVersion.addError(intermediateVersion.length() - 1, 73);
 		}
	}
	
    /** 
     * Parses all operand fields for instructions with operand modes identical
	 * to IOWD (should only be IOWD)
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/07/09 - Tobin Chee<br>
	 * 		- Deleted an unneccesary call to tokenizer.getNextToken()
	 */
	private static void parseOperandsIOWD2(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, int[] locationCounter) {
		
		if(parseOperandMem(t, sourceLine, token, type, locationCounter) == SourceProgramStatus.NORMAL){
			
			if(sourceLine.length() > 0){
				t.getNextToken(sourceLine, token, type);
				
				if(type[0] == TokenType.COMMA){
					
					if(parseOperandXR(t, sourceLine, token, type, locationCounter) == SourceProgramStatus.NORMAL){
						
						if(sourceLine.length() > 0){
							t.getNextToken(sourceLine, token, type);
							
							if(type[0] == TokenType.COMMA){
								
								if(parseOperandIOWDFlag(t, sourceLine, token, type, locationCounter) == SourceProgramStatus.NORMAL){
									parseEndOfLine(sourceLine, t, token, type);
								}
							}
							else{
								//nfe exp comma between operands
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length() - 1, 45);
							}
						}
						else{
							//nfe unex eol							
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 1);
						}
					}
				}
				else{
					//nfe exp comma between operands
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 45);
				}
			}
			else{
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 1);
			}
		}
	}
	
	/** Parse operand field where XR is used.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @return true, if the parser has encountered the end of the program "FINISH"<br>
	 *         false, otherwise
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- No changes
	 */
	private static SourceProgramStatus parseOperandXR(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, int[] locationCounter){
		
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			
			if(type[0] == TokenType.DATA){
				
				try{
					int xr = Integer.parseInt(token.toString());
					
					if((xr >= 1) && (xr <= 7)){
						intermediateVersion.updateIndexRegister(intermediateVersion.length()- 1, xr);
						return SourceProgramStatus.NORMAL;
					}
					else{
						//nfe index register should be between 1 and 7 (inclusive)						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 10);
						return SourceProgramStatus.NON_FATAL_ERROR;

					}
				} catch(NumberFormatException nfe){
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
					return SourceProgramStatus.NON_FATAL_ERROR;
				}
			}
			else if(type[0] == TokenType.MNEMONIC){
				
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						int xr = symbolTable.getEQUValue(token.toString());
						
						if((xr >= 1) && (xr <= 7)){
							intermediateVersion.updateIndexRegister(intermediateVersion.length()- 1, xr);
							return SourceProgramStatus.NORMAL;
						}
						else{
							//nfe exp integer 1 <= x <= 7				
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 10);
							return SourceProgramStatus.NON_FATAL_ERROR;
						}
					}
					else{
						//nfe int, equ or blank op						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 33);
						return SourceProgramStatus.NON_FATAL_ERROR;
					}
				}
				else{
					//nfe int, equ or blank op
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 33);
					return SourceProgramStatus.NON_FATAL_ERROR;
				}
			}
			else if(type[0] == TokenType.COMMA){
				sourceLine.insert(0, token);
				intermediateVersion.updateIndexRegister(intermediateVersion.length() - 1, 0); //Invalid value 0 denotes no index register adjustment
				return SourceProgramStatus.NORMAL;
			}
			else{
				//nfe int, equ or blank op					
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 33);
				return SourceProgramStatus.NON_FATAL_ERROR;
			}
		}
		else
		{
			//nfe unex eol									
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
			return SourceProgramStatus.NON_FATAL_ERROR;
		}
	}
	
	/** Parse operand field when IOWD flag is used.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @return true, if the parser has encountered the end of the program "FINISH"<br>
	 *         false, otherwise
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- No changes
	 */
	private static SourceProgramStatus parseOperandIOWDFlag(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, int[] locationCounter){
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			
			if(type[0] == TokenType.DATA){
				
				try{
					int flag = Integer.parseInt(token.toString());
					if((flag >= 0) && (flag <= 3)){
						intermediateVersion.updateIOWDFlag(intermediateVersion.length()- 1, flag);
						return SourceProgramStatus.NORMAL;
					}
					else{
						//nfe IOWD flag should be between 0 and 3 (inclusive)
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 12);
						return SourceProgramStatus.NON_FATAL_ERROR;
					}
				} catch(NumberFormatException nfe){						
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
					return SourceProgramStatus.NON_FATAL_ERROR;
				}
			}
			else if(type[0] == TokenType.MNEMONIC){
				
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						int IOFlag = symbolTable.getEQUValue(token.toString());
						
						if((IOFlag >= 0) && (IOFlag <= 3)){
							intermediateVersion.updateIOWDFlag(intermediateVersion.length()- 1, IOFlag);
							return SourceProgramStatus.NORMAL;
						}
						else{
							//nfe exp integer 0 <= x <= 3
							
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 12);
							return SourceProgramStatus.NON_FATAL_ERROR;
						}
					}
					else{
						//nfe exp predefined EQU value
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 11);
						return SourceProgramStatus.NON_FATAL_ERROR;
					}
				}
				else{
					//nfe exp predefined EQU value
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
					return SourceProgramStatus.NON_FATAL_ERROR;
				}
			}
			else{
				//nfe exp integer value
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 11);
				return SourceProgramStatus.NON_FATAL_ERROR;
			}
		}
		else
		{
			//nfe unex eol
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
			return SourceProgramStatus.NON_FATAL_ERROR;
		}
	}
	
	/** 
	 * Parse operand field when a memory location is used.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @return true, if the parser has encountered the end of the program "FINISH"<br> false, otherwise
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Updated documentation.<br><br>
	 * 	- 05/11/09 - Tobin Chee<br>
	 * 		- Commented out unnecessary calls defining symbols.
	 */
	private static SourceProgramStatus parseOperandMem(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, int[] locationCounter){
		
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 0);
			
			if(type[0] == TokenType.MNEMONIC){
							
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == Assembler.SymbolUsage.EQU_VALUE){
						int addr = symbolTable.getEQUValue(token.toString());

						if((addr >= MIN_16BIT) && (addr <= MAX_16BIT)){
							intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
							return SourceProgramStatus.NORMAL;
						}
						else{
							//NFE exp valid Integer mem address x, such that (-2^15 <= addr <= 2^15 - 1)
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 13);
							return SourceProgramStatus.NON_FATAL_ERROR;
						}
					}
					else{ //if symbol is a data label
						ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
						intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
						return SourceProgramStatus.NORMAL;
					}
				}
				else{
					//Symbol symb = new Symbol();
					//symb.setLabel(token.toString());
					//symb.setUsage(SymbolUsage.DATA_LABEL);
					ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
					intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
					return SourceProgramStatus.NORMAL;
				}
			} 
			else if(type[0] == TokenType.DATA){
				try{
					int addr = Integer.parseInt(token.toString());
					
					if((addr >= MIN_16BIT) && (addr <= MAX_16BIT)){
						intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
						return SourceProgramStatus.NORMAL;
					}
					else{
						//NFE exp valid Integer mem address x, such that (-2^15 <= x <= 2^15 - 1)
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 13);
						return SourceProgramStatus.NON_FATAL_ERROR;
					}
				} catch(NumberFormatException nfe){
					// NFE exp valid Integer
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
					return SourceProgramStatus.NON_FATAL_ERROR;
				}
			} 
			else if(type[0] == TokenType.INDIRECT){
				intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 1);
				
				if(sourceLine.length() > 0){
					t.getNextToken(sourceLine, token, type);
					
					if(type[0] == TokenType.MNEMONIC){
						
						if(symbolTable.symbolIsDefined(token.toString())){
							
							if(symbolTable.getUsage(token.toString()) == Assembler.SymbolUsage.EQU_VALUE){
								int addr = symbolTable.getEQUValue(token.toString());

								if((addr >= MIN_16BIT) && (addr <= MAX_16BIT)){
									intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
									return SourceProgramStatus.NORMAL;
								}
								else{
									//NFE exp valid Integer mem address x, such that (-2^15 <= addr <= 2^15 - 1)
									
									intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
									intermediateVersion.addError(intermediateVersion.length() - 1, 13);
									return SourceProgramStatus.NON_FATAL_ERROR;
								}
							}
							else{ //if symbol is a data label
								ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
								intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
								return SourceProgramStatus.NORMAL;
							}
						}
						else{
							//Symbol symb = new Symbol();
							//symb.setLabel(token.toString());
							//symb.setUsage(SymbolUsage.DATA_LABEL);
							ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
							intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
							return SourceProgramStatus.NORMAL;
						}
					} 
					else if(type[0] == TokenType.DATA){
			
						try{
							int addr = Integer.parseInt(token.toString());
							
							if((addr >= MIN_16BIT) && (addr <= MAX_16BIT)){
								intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
								return SourceProgramStatus.NORMAL;
							}
							else{
								//NFE exp valid Integer mem address x, such that x is a valid 16 bit two's comp integer
								
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length() - 1, 13);
								return SourceProgramStatus.NON_FATAL_ERROR;
							}
						} catch(NumberFormatException nfe){
							// NFE exp valid Integer, symbol or equ value
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 8);
							return SourceProgramStatus.NON_FATAL_ERROR;
						}
					}
					else{
						//nfe exp predefined equ or int
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 8);
						return SourceProgramStatus.NON_FATAL_ERROR;
					}
				}
				else{
					//nfe unex EOL
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 1);
					return SourceProgramStatus.NON_FATAL_ERROR;
				}
			}
			else if(type[0] == TokenType.ARITHMETIC){
				
				if(token.toString().compareTo("*") == 0){
					int addr = locationCounter[0];
					
					ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
					exp.updateTermValue(exp.length() - 1, addr);
					return parseSecondOperandStarNotation(t, sourceLine, token, type, exp);
				}
				else{
					//NFE exp addr (label, # or * notation or %)
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 9);
					return SourceProgramStatus.NON_FATAL_ERROR;
				}
			}
			else{
				//NFE exp addr (label, # or * notation or %)
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 9);
				return SourceProgramStatus.NON_FATAL_ERROR;
			}
		}
		else{
			//NFE unex EOL
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
			return SourceProgramStatus.NON_FATAL_ERROR;
		}
	}
    
	/** 
	 * Parses potential mathematical operands following star notation. This method is called by
	 * parseOperandMem which is a submethod for parseOperandsIOWD to simplify the task.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param exp ArithmeticExpression to which to add following operands.
	 * @return true, if the parser has encountered the end of the program "FINISH"<br>
	 *         false, otherwise
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/05/09 - Tobin Chee<br>
	 * 		- Updated documentation.<br><br>
	 */
	private static SourceProgramStatus parseSecondOperandStarNotation(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, ArithmeticExpression exp){
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			
			if((token.toString().compareTo("+") == 0) ||
					(token.toString().compareTo("-") == 0)){
				ArithmeticExpression.ArithmeticOperator starOp = ArithmeticExpression.ArithmeticOperator.DIVIDE;
				
				if(token.toString().compareTo("+") == 0){
					starOp = ArithmeticExpression.ArithmeticOperator.ADD;
				}
				else if(token.toString().compareTo("-") == 0){
					starOp = ArithmeticExpression.ArithmeticOperator.SUBTRACT;
				}
				
				if(sourceLine.length() > 0){
					t.getNextToken(sourceLine, token, type);
					
					if(type[0] == TokenType.DATA){
						
						try{
							int x = Integer.parseInt(token.toString());
							
							exp.defineTermOperandPair(x, ArithmeticExpression.Sign.POSITIVE, starOp);
							x = exp.evaluate();
							
							if((x >= (-Math.pow(2, 15))) && (x <= (Math.pow(2, 15) - 1))){
								intermediateVersion.updateAddr(intermediateVersion.length() - 1, x);
								return SourceProgramStatus.NORMAL;
							}
							else{
								//NFE exp integer is valid 16 bit two's comp
								
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length() - 1, 13);
								return SourceProgramStatus.NON_FATAL_ERROR;
							}
						} catch(NumberFormatException nfe){
							//NFE exp valid integer after *+
							
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 11);
							return SourceProgramStatus.NON_FATAL_ERROR;
						}
					}
					else if(type[0] == TokenType.MNEMONIC){
						
						if(symbolTable.symbolIsDefined(token.toString())){
							
							if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
								int x = symbolTable.getEQUValue(token.toString());
								exp.defineTermOperandPair(x, ArithmeticExpression.Sign.POSITIVE, starOp);
								x = exp.evaluate();
								
								if((x >= (-Math.pow(2, 15))) && (x <= (Math.pow(2, 15) - 1))){
									intermediateVersion.updateAddr(intermediateVersion.length() - 1, x);
									return SourceProgramStatus.NORMAL;
								}
								else{
									//NFE exp integer is valid 16 bit two's comp
									
									intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
									intermediateVersion.addError(intermediateVersion.length() - 1, 13);
									return SourceProgramStatus.NON_FATAL_ERROR;
								}
							}
							else{
								//nfe exp predefined equated symbol
								
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length() - 1, 11);
								return SourceProgramStatus.NON_FATAL_ERROR;
							}
						}
						else{
							//nfe exp predefined equated symbol
							
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 11);
							return SourceProgramStatus.NON_FATAL_ERROR;
						}
					}
					else{
						//NFE exp symbol label or integer value after "*+" and "*-"
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 14);
						return SourceProgramStatus.NON_FATAL_ERROR;
					}
				}
				else{
					//NFE unex EOL
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 1);

					return SourceProgramStatus.NON_FATAL_ERROR;
				}
			}
			else if(type[0] == TokenType.COMMA){
				intermediateVersion.updateAddr(intermediateVersion.length() - 1, exp.evaluate());
				sourceLine.insert(0, token);
				return SourceProgramStatus.NORMAL;
			}
			else{
				//NFE exp separator or arithmetic after star
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 5);
				return SourceProgramStatus.NON_FATAL_ERROR;
			}
		}
		else{
			//NFE unex EOL
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
			return SourceProgramStatus.NON_FATAL_ERROR;
		}
	}
	
	/** Parse operand field for specific instruction DEC directive.<Br>
	 * Extracts the operand for the DEC directive.
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- No changes
	 */
	private static void parseOperandsDEC(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter){
		String valueStr = parseNumeric(t, sourceLine, token, type, locationCounter);
			
		try{
			long value = Long.parseLong(valueStr, 10);
			
			if((value >= MIN_32BIT) && (value <= MAX_32BIT)){
				intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, (int) value);
				parseEndOfLine(sourceLine, t, token, type);
			}
			else{
				//nfe severe value out of range. Must be a valid 32 bit two's complement value (-2^31 <= x <= 2^31 - 1)
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 21);
			}
		} catch(NumberFormatException nfe){
			//error expecting valid decimal integer
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 11);
		}

	}
	
	/** Parse operad field for specific instruction OCT directive.<br>
	 * Extracts the operand for the OCT directive.
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/13/09 - Tobin Chee<br>
	 * 		- Replaced redundant code with a call to convertTwosCompToDec()<br>
	 * 		- Changed variable value from an int to a long.
	 */
	private static void parseOperandsOCT(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter){
		String valueStr = parseNumeric(t, sourceLine, token, type, locationCounter);
		
		try{
			long value = Long.parseLong(valueStr, 8);	
			StringBuffer sbValue = new StringBuffer(Long.toBinaryString(value));
			
			if(sbValue.length() <= 32) {
				
				while(sbValue.length() < 32){ //pad with zeroes to make a valid 2's comp integer
					sbValue.insert(0, "0");
				}
				value = convertTwosCompToDec(sbValue);
				
				if((value >= MIN_32BIT) && (value <= MAX_32BIT)){
					intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, (int) value);
					parseEndOfLine(sourceLine, t, token, type);
				}
				else{
					//nfe severe value out of range. Must be a valid 32 bit two's complement value (-2^31 <= x <= 2^31 - 1)
					
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 21);
				}
			}
			else{
				//nfe severe value out of range. Must be a valid 32 bit two's complement value (-2^31 <= x <= 2^31 - 1)
				
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 21);
			}
		} catch(NumberFormatException nfe){
			//error expecting valid octal integer
			
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 19);
		}
	}
	
	/** Parse operand field for specitic instruction HEX directive.<br>
	 * Extracts the operand for the HEX directive.
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 05/13/09 - Tobin Chee<br>
	 * 		- Replaced redundant code with a call to convertTwosCompToDec()<br>
	 * 		- Changed variable value from an int to a long.
	 */
	private static void parseOperandsHEX(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter){
		String valueStr = parseNumeric(t, sourceLine, token, type, locationCounter);
		
		try{
			long value = Long.parseLong(valueStr, 16);
			StringBuffer sbValue = new StringBuffer(Long.toBinaryString(value));
			
			if(sbValue.length() <= 32) {
				
				while(sbValue.length() < 32){ //pad with zeroes to make a valid 2's comp integer
					sbValue.insert(0, "0");
				}
				value = convertTwosCompToDec(sbValue);
				
				if((value >= MIN_32BIT) && (value <= MAX_32BIT)){
					intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, (int) value);
					parseEndOfLine(sourceLine, t, token, type);
				}
				else{
					//nfe severe value out of range. Must be a valid 32 bit two's complement value (-2^31 <= x <= 2^31 - 1)			
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 21);
				}
			}
			else{
				//nfe severe value out of range. Must be a valid 32 bit two's complement value (-2^31 <= x <= 2^31 - 1)		
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 21);
			}
		} catch(NumberFormatException nfe){
			//error expecting valid hex integer		
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 18);
		}
	}
	
	/**
	 * Returns the signed magnitude form decimal integer value corresponding to the two's complement string given
	 * in the operand fields for the HEX and OCT directives.
	 * 
	 * Requires: sbValue must be a binary formatted string of 32-bits or less. Any binary
	 * strings less than 32-bits will be right justified, and padded with zeroes.
	 * 
	 * @param sbValue two's complement string
	 * @return signed magnitude decimal value of sbValue
	 * 
	 * Change Log:<br>
	 * 	- 05/16/09 - Tobin Chee<br>
	 * 		- Changed start and end to final variables.<br>
	 * 		- Fixed indexing errors with start and end.
	 */
	private static int convertTwosCompToDec(StringBuffer sbValue){
		int value = 0;
		Integer[] binaryCode = new Integer[32];
		final int start = 0;
		final int end = 31;
		
		for(int i = start; i <= end; i++){
			String temp = sbValue.substring(i, i+1);
			binaryCode[i] = Integer.parseInt(temp);
		}
		
		if(binaryCode[start] == 1){ //if negative
			Boolean firstOneDetected = false;
			
			for(int i = end; i >= start; i--){
				double result = Math.pow(2, end - i);
				
				if(firstOneDetected){
					value -= Math.abs(binaryCode[i] - 1) * (long)result;
				}
				else{
					
					if(binaryCode[i] == 1){
						firstOneDetected = true;
					}
					value -= (long)binaryCode[i] * (long)result;
				}
			}
		}
		else{ //if positive
			
			for(int i = start; i <= end; i++){
				int result = (int)(Math.pow(2, end - i));
				value += binaryCode[i] * result;
			}
		}
		return value;
		
	}
	
	/** Parse numereic from operand field.<br>
	 * Helper method for parseOperands HEX, DEC and OCT
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 04/25/09 - Tobin Chee<br>
	 * 		- No longer returns errors when alphabetic strings are found in the operand field to 
	 * accomodate HEX numbers.
	 */
	private static String parseNumeric(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter){
		
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			
			
			if(type[0] == TokenType.DATA){
				return token.toString();
			}
			else if(type[0] == TokenType.MNEMONIC){
				
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						return String.valueOf(symbolTable.getEQUValue(token.toString()));
					}
					else{
						//REVISION - don't return error, if a symbol named "FFF" is found we want to return it just in case
						return token.toString();
						
						//nfe exp integer or equ value
						//TODO log error
						//return "error";
					}
				}
				else{
					//REVISION - don't return error, if a symbol named "FFF" is found we want to return it just in case
					return token.toString();
					
//					//nfe exp predefined equ or integer value
//					//TODO log error
//					return "error";
					
				}
			}
			else if(type[0] == TokenType.ARITHMETIC){
				String sign = "";
				if((token.toString().compareTo("+") == 0) ||
						(token.toString().compareTo("-") == 0)){
					
					if(token.toString().compareTo("-") == 0){
						sign = "-";
					}
					
					if(sourceLine.length() > 0){
						t.getNextToken(sourceLine, token, type);
						
						if(type[0] == TokenType.DATA){
							token.insert(0, sign);
							return token.toString();
						}
						else if(type[0] == TokenType.MNEMONIC){
							
							if(symbolTable.symbolIsDefined(token.toString())){
								
								if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
									String.valueOf(symbolTable.getEQUValue(token.toString()));
									StringBuffer result = new StringBuffer(sign + String.valueOf(symbolTable.getEQUValue(token.toString())));
									return result.toString();
								}
								else{
									//REVISION - don't return error, if a symbol named "FFF" is found we want to return it just in case
									token.insert(0, sign);
									return token.toString();
									
									//nfe exp integer or equ value
									//TODO log error
									//return "error";
								}
							}
							else{
								//REVISION - don't return error, if a symbol named "FFF" is found we want to return it just in case
								token.insert(0, sign);
								return token.toString();
								///nfe exp predefined equ or integer value
								//TODO log error
							}
						}
						else{
							//nfe error, exp sign, numeric or label
							//TODO log error
							return "error";
						}
					}
					else{
						//nfe severe unex EOL
						//TODO log error
						return "error";
					}
					
				}
				else{
					//nfe error, exp sign, numeric or label
					//TODO log error
					return "error";
				}
			}
			else{
				//nfe exp numeric value (dec, hex, oct)
				//TODO log error
				return "error";
			}
		}
		else{
			//nfe severe unex EOL
			//TODO log error
			return "error";
		}
	}
	
	/** Parse operand field for specific instruction CALL.<br>
	 * Extracts the operands for the CALL instruction.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Dan Carpenter
	 * 
	 * Change Log:<br>
	 *  - 04/22/09 - Dan Carpenter<br>
	 * 		- Created skeleton for procedure.<br><br>
	 *  - 04/27/09 - Dan Carpenter<br>
	 * 		- Filled in skeleton.<br><br>
	 *  - 04/28/09 - Dan Carpenter<br>
	 * 		- Created skeleton for procedure.<br><br>
	 *  - 04/28/09 - Dan Carpenter<br>
	 * 		- Procedure is complete and ready for testing.<br><br>
	 *  - 04/28/09 - Dan Carpenter<br>
	 * 		- Fixed some bugs.<br><br>
	 *  - 04/28/09 - Dan Carpenter<br>
	 * 		- Procedure is complete and tested.
	 */
	private static void parseOperandsCALL(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, int[] locationCounter) {
		
		
		@SuppressWarnings("unused")
		SourceProgramStatus stat = parseOperandMem(t, sourceLine, token, type, locationCounter);
		
		if (sourceLine.length() > 0) {
			t.getNextToken(sourceLine, token, type);
			if(type[0] == TokenType.COMMA) {
				stat = parseOperandXR(t, sourceLine, token, type, locationCounter);
			}
			else { //error: COMMA expected
				intermediateVersion.addError(intermediateVersion.length() - 1, 45);
				intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			}
			parseEndOfLine(sourceLine, t, token, type);
		}
		else {		//error: unexpected end of line
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
	}
	

	/** Parse operand field for specific instruction PRMID directive.<br>
	 * Extracts the list name and list length from sourceLine.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Sam Jones
	 * 
	 * Change Log: <br>
	 * 	-04/20/09 - Sam Jones<br>
	 * 		- Created method.<br><br>
	 * 	-04/27/09 - Sam Jones<br>
	 * 		- Tested and debugged.
	 */
	private static void parseOperandsPRMID(Tokenizer t,
			StringBuffer sourceLine, StringBuffer token, TokenType[] type,
			int[] locationCounter) {
		if (sourceLine.length() == 0) {
			// error unexpected EOL
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
			//intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));

		}
		else {
			t.getNextToken(sourceLine, token, type);
			if (type[0] != TokenType.MNEMONIC) {
				// error expected label
				intermediateVersion.addError(intermediateVersion.length() - 1, 15);
				//intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));

			}
			else if (symbolTable.symbolIsDefined(token.toString())) {
				// error symbol exists
				intermediateVersion.addError(intermediateVersion.length() - 1, 52);
				//intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));

			}
			else if (symbolTable.containsPRMID()) {
				// error already contains PRMID
				intermediateVersion.addError(intermediateVersion.length() - 1, 40);
				//intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));

			}
			else if (sourceLine.length() == 0) {
				// error unexpected EOL
				//intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));
				intermediateVersion.addError(intermediateVersion.length() - 1, 1);

			}
			else {
				String label = token.toString();
				t.getNextToken(sourceLine, token, type);
				if (type[0] != TokenType.COMMA) {
					// error expected comma
					intermediateVersion.addError(intermediateVersion.length() - 1, 39);
					//intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));

				}
				else if (sourceLine.length() == 0) {
					// error unexpected EOL
					intermediateVersion.addError(intermediateVersion.length() - 1, 1);
					//intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));

				}
				else {
					t.getNextToken(sourceLine, token, type);
					
					try{
						int value = Integer.parseInt(token.toString());
						Symbol newPRMID = new Symbol();
						newPRMID.setLabel(label);
						newPRMID.setUsage(SymbolUsage.PRMID);
						newPRMID.setEquValue(value);
						newPRMID.setLocation(locationCounter[0]);
						symbolTable.defineSymbol(newPRMID);
						PRMLSTcount = value;
						parseEndOfLine(sourceLine, t, token, type);
					} catch(NumberFormatException nfe){
						//nfe exp valid integer as second parameter
						//TODO do we want a limit on the length of our PRMLST?
						intermediateVersion.addError(intermediateVersion.length() - 1, 11);
					}
				}
			}
		}
	}

	/** Parse operand field for specific instruction PRMLST.<br>
	 * Extracts the symbol name operand from sourceLine.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Meghan Day
	 * 
	 * Change Log:<br>
	 *  - 04/27/09 - Meghan Day<br>
	 *  	- Created, filled in, and documented procedure<br><br>
	 *  - 04/29/09 - Tobin Chee<br>
	 *  	- Rewrote method and commented out old code.<br><br>
	 *  - 04/30/09 - Tobin Chee<br>
	 *  	- Commented out unnecessary call defining symbols.<br><br>
	 *  - 05/05/09 - Meghan Day<br>
	 *  	- Fixed error messages
	 */
	private static void parseOperandsPRMLST(Tokenizer t,
			StringBuffer sourceLine, StringBuffer token, TokenType[] type,
			int[] locationCounter) {
		if((PRMLSTcount > 0)){
			if(sourceLine.length() > 0){
				intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 3); //set addr flag to PRMLST
				t.getNextToken(sourceLine, token, type);
				
				if(type[0] == TokenType.MNEMONIC){
					
					if(symbolTable.symbolIsDefined(token.toString())){
						
						if(symbolTable.getUsage(token.toString()) == Assembler.SymbolUsage.EQU_VALUE){
							int addr = symbolTable.getEQUValue(token.toString());
	
							if((addr >= MIN_16BIT) && (addr <= MAX_16BIT)){
								intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
								PRMLSTcount--;
								parseEndOfLine(sourceLine, t, token, type);
							}
							else{
								//NFE exp valid Integer mem address x, such that (-2^15 <= addr <= 2^15 - 1)
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length() - 1, 13);
								PRMLSTcount = 0;
							}
						}
						else{ //if symbol is a data label
							ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
							intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
							PRMLSTcount--;
							parseEndOfLine(sourceLine, t, token, type);
						}
					}
					else{
						//Symbol symb = new Symbol();
						//symb.setLabel(token.toString());
						//symb.setUsage(SymbolUsage.DATA_LABEL);
						ArithmeticExpression exp = new ArithmeticExpression(token.toString(), ArithmeticExpression.Sign.POSITIVE);
						intermediateVersion.updateOperandSymbolExpression(intermediateVersion.length() - 1, exp);
						PRMLSTcount--;
						parseEndOfLine(sourceLine, t, token, type);
					}
				} 
				else if(type[0] == TokenType.DATA){
					try{
						int addr = Integer.parseInt(token.toString());
						
						if((addr >= MIN_16BIT) && (addr <= MAX_16BIT)){
							intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
							PRMLSTcount--;
							parseEndOfLine(sourceLine, t, token, type);
						}
						else{
							//NFE exp valid Integer mem address x, such that (-2^15 <= x <= 2^15 - 1)
							
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 13);
							PRMLSTcount = 0;
						}
					} catch(NumberFormatException nfe){
						// NFE exp valid Integer
						
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 11);
						PRMLSTcount = 0;
					}
				} 
				else if (token.charAt(0) == ':') {
					// comment, missing operand
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 96);
				}
				else{
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 8);
					PRMLSTcount = 0;
				}
			}
			else{
				//nfe exp EOL
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 1);
				PRMLSTcount = 0;
			}
		}
		else{
			//nfe exp PRMLST must follow directly after PRMID call, and is limited to the length defined by PRMID
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 47);
			PRMLSTcount = 0;
		}
		
		/*if (sourceLine.length() > 0) {
			t.getNextToken(sourceLine, token, type);
			if (type[0] == TokenType.MNEMONIC) {
				if (symbolTable.symbolIsDefined(token.toString())) {
					symbolTable.UpdateUsage(token.toString(), SymbolUsage.PRMLST);
				}
				else {
					// could either add the symbol and resolve in pass 2 or report an error
					// choosing to define and resolve later
					Symbol prmlst = new Symbol();
					prmlst.setLabel(token.toString());
					prmlst.setUsage(SymbolUsage.PRMLST);
					symbolTable.defineSymbol(prmlst);
					parseEndOfLine(sourceLine, t, token, type);
				}
			}
			else {
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 15);
			}
		}
		else {
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}*/
	}

	/** Parse operand field when a string is used.<br>
	 * Extracts the string operand from sourceLine.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Dan Carpenter
	 * 
	 * - 04/21/09 - Dan Carpenter<br>
	 * 		- Created skeleton for procedure.<br><br>
	 *  - 04/21/09 - Dan Carpenter<br>
	 * 		- Procedure is complete and ready for testing<br><br>
	 *  - 04/21/09 - Dan Carpenter<br>
	 * 		- Initial bugs have been fixed. Continuing testing.<br><br>
	 *  - 04/25/09 - Dan Carpenter<br>
	 * 		- Created skeleton for procedure.<br><br>
	 *  - 04/27/09 - Dan Carpenter<br>
	 * 		- Added error: String too long<br><br>
	 *  - 04/27/09 - Dan Carpenter<br>
	 * 		- Fixed some bugs<br><br>
	 *  - 04/27/09 - Dan Carpenter<br>
	 * 		- Procedure is complete and fully tested
	 */
	private static void parseOperandsString(Tokenizer t,
			StringBuffer sourceLine, StringBuffer token, TokenType[] type,
			int[] locationCounter) {
		char ch;
		int count = 0, ascii = 0;
		StringBuffer str = new StringBuffer();
		if(sourceLine.length() > 0) {
			t.getNextToken(sourceLine, token, type);
			if(type[0] != Assembler.TokenType.SINGLE_QUOTE) { //Single quote expected
				intermediateVersion.addError(intermediateVersion.length() - 1, 2);
				intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			}
			else {
				if(sourceLine.length() > 0) {
					t.getNextToken(sourceLine, token, type);
					while (type[0] != TokenType.SINGLE_QUOTE && sourceLine.length() > 0) {
						str.append(token);
						if(sourceLine.length() > 0) {
							t.getNextToken(sourceLine, token, type);
						}
						else { //EOL unexpected
							intermediateVersion.addError(intermediateVersion.length() - 1, 1);
							intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						}	
					}
						
					if (str.length() > 4) { //error: character string exceeded 4 characters
						intermediateVersion.addError(intermediateVersion.length() - 1, 35);
						intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					}
					else if (type[0] != TokenType.SINGLE_QUOTE) {
						intermediateVersion.addError(intermediateVersion.length() - 1, 2);
						intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					}
					else {						
						while(count < str.length()) {
							ch = str.charAt(count);
							ascii = ascii * 256 + ch;
							count++;
						}
					}
					
					while(count < 4) {
						ascii = ascii * 256 + 32;
						count++;
					}
					intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, ascii);
					parseEndOfLine(sourceLine,t,token,type);
				}
				else { //EOL unexpected
					intermediateVersion.addError(intermediateVersion.length() - 1, 1);
					intermediateVersion.updateInstructionCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				}
				
			}
		}
	}

	/** Parse operand field for specific instruction EXTRN directive.<br>
	 * Extracts the extrn operand from sourceLine.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Meghan Day
	 * 
	 * Change Log:<br>
	 * 	- 04/20/09 - Meghan Day<br>
	 * 		- Began filling in procedure body.<br><br>
	 *  - 04/22/09 - Meghan Day<br>
	 *  	- Filled out documentation.<br><br>
	 *  - 04/25/09 - Meghan Day<br>
	 *  	- Filled in error codes.<br><br>
	 *  - 04/26/09 - Meghan Day<br>
	 *  	- Filled in remaining error code.<br><br>
	 *  - 04/27/09 - Meghan Day<br>
	 *  	- Fixed some errors.
	 */
	private static void parseOperandsEXTRN(Tokenizer t,
			StringBuffer sourceLine, StringBuffer token, TokenType[] type,
			int[] locationCounter) {

		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			
			if (type[0] == TokenType.MNEMONIC) {

				if (!symbolTable.symbolIsDefined(token.toString())) {
					Symbol operand = new Symbol(token.toString(), -1, SymbolUsage.EXTRN);
					symbolTable.defineSymbol(operand);
					parseEndOfLine(sourceLine, t, token, type);
				}
				else { //symbol is defined
					if ((symbolTable.getUsage(token.toString()) == SymbolUsage.DATA_LABEL) &&
							(symbolTable.getLocation(token.toString()) == -1)) {
						symbolTable.UpdateUsage(token.toString(), SymbolUsage.EXTRN);
						parseEndOfLine(sourceLine, t, token, type);
					}
					else {
						// error, trying to extrn an already extrned symbol
						intermediateVersion.addError(intermediateVersion.length() - 1, 42);
						parseEndOfLine(sourceLine, t, token, type);
					}
				}
			}
			else {
				intermediateVersion.addError(intermediateVersion.length() - 1, 15);
			}
		}
		else {
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
	}
	
	/** Parse operand field for specific instruction AVERT directive.<br>
	 * Extracts the extrn operand from sourceLine.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
	 * 
	 * Change Log:
	 * 	- 04/20/09 - Meghan Day
	 * 		- Began filling in procedure body
	 *  - 04/22/09 - Meghan Day
	 *  	- Filled out documentation
	 *  - 04/25/09 - Meghan Day
	 *  	- Filled in error codes
	 *  - 04/26/09 - Meghan Day
	 *  	- Filled in remaining error code
	 *  - 04/27/09 - Meghan Day
	 *  	- Fixed some errors
	 *  - 05/12/09 - Tobin Chee
	 *  	- AVERT now stores the line of the source program on which it appears in the EQU_VALUE in the symbolTable
	 *  	to allow error logging to it later.
	 */
	private static void parseOperandsAVERT(Tokenizer t,
			StringBuffer sourceLine, StringBuffer token, TokenType[] type,
			int[] locationCounter) {

		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			
			if (type[0] == TokenType.MNEMONIC) {

				if (!symbolTable.symbolIsDefined(token.toString())) {
					Symbol operand = new Symbol(token.toString(), -1, SymbolUsage.AVERT);
					operand.setEquValue(intermediateVersion.length() - 1);
					symbolTable.defineSymbol(operand);
					parseEndOfLine(sourceLine, t, token, type);
				}
				else { //if symbol is already defined
					if ((symbolTable.getUsage(token.toString()) == SymbolUsage.DATA_LABEL)) {
						symbolTable.updateEQUValue(token.toString(), intermediateVersion.length() - 1);
						symbolTable.UpdateUsage(token.toString(), SymbolUsage.AVERT);
						parseEndOfLine(sourceLine, t, token, type);
					}
					else {
						// error, cannot AVERT only accepts a single data label in the operand field.
						intermediateVersion.addError(intermediateVersion.length() - 1, 41);
						parseEndOfLine(sourceLine, t, token, type);
					}
				}
			}
			else {
				intermediateVersion.addError(intermediateVersion.length() - 1, 15);
			}
		}
		else {
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
	}

	/** Parse operand field for specific instruction EXR.<br>
	 * Extracts the operands for the instruction EXR.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Sam Jones
	 * 
	 * Change Log:<br>
	 * 	-4/20 - Sam Jones<br>
	 * 		- Created method.<br><br>
	 * 	-4/27 - Sam Jones<br>
	 * 		- Tested and debugged.
	 */
	private static void parseOperandsEXR(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, int[] locationCounter) {
		if (sourceLine.length() == 0 ) {
			// error unexpected EOL
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));
		}
		else {
			t.getNextToken(sourceLine, token, type);
			if (type[0] != Assembler.TokenType.DATA) {
				// error expected DATA
				intermediateVersion.addError(intermediateVersion.length() - 1, 11);
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));
			}
			else if (Integer.valueOf(token.toString()) < 1 || Integer.valueOf(token.toString()) > 7) {
				// error invalid number
				intermediateVersion.addError(intermediateVersion.length() - 1, 10);
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));
			}
			else if (sourceLine.length() == 0) {
				// error unexpected EOL
				intermediateVersion.addError(intermediateVersion.length() - 1, 1);
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));
			}
			else {
				int XRfirst = Integer.valueOf(token.toString()); 
				t.getNextToken(sourceLine, token, type);
				if (type[0] != Assembler.TokenType.COMMA) {
					// error expected comma
					intermediateVersion.addError(intermediateVersion.length() - 1, 39);
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));
				} else if (sourceLine.length() == 0) {
					// error unexpected EOL
					intermediateVersion.addError(intermediateVersion.length() - 1, 1);
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));
				} else {
					t.getNextToken(sourceLine, token, type);
					if (type[0] != Assembler.TokenType.DATA) {
						// error expected DATA
						intermediateVersion.addError(intermediateVersion.length() - 1, 11);
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));
					} else if (Integer.valueOf(token.toString()) < 1 || Integer.valueOf(token.toString()) > 7) {
						// error invalid number
						intermediateVersion.addError(intermediateVersion.length() - 1, 10);
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, Integer.valueOf(machineOps.getHexCode("NOP")));
					} else {
						intermediateVersion.updateIndexRegister(intermediateVersion.length() - 1, Integer.valueOf(token.toString()));
						intermediateVersion.updateAddr(intermediateVersion.length() - 1, XRfirst);
						parseEndOfLine(sourceLine, t, token, type);
					}
				}
			}
		}
	}

	/** Parses operand field when a number or equated symbol is used.<br>
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Meghan Day
	 * 
	 * Change Log:<br>
	 * 	- 04/20/09 - Meghan Day<br>
	 * 		- Began filling in procedure body.<br><br>
	 *	- 04/21/09 - Tobin Chee<br>
	 *		- Changed method name from parseNumOrEQU to parseOperandsNumOrEQU to be more consistent 
	 * with rest of program.<br><br>
	 *  - 04/22/09 - Meghan Day<br>
	 *  	- Filled out documentation.<br><br>
	 *  - 04/25/09 - Meghan Day<br>
	 *  	- Fixed some errors and filled in error codes.<br><br>
	 *  - 04/26/09 - Meghan Day<br>
	 *  	- Tweaked documentation.<br><br>
	 *  - 04/27/09 - Meghan Day<br>
	 *  	- Rearranged code trivially.<br><br>
	 *  - 05/05/09 - Meghan Day<br>
	 *  	- Made error messages more specific.<br><br>
	 *  - 05/17/09 - Meghan Day<br>
	 *  	- Changed to only accept operands greater than or equal to 0.
	 */
	private static void parseOperandsNumOrEQU(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, int[] locationCounter) {
		
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 2);
			
			if(type[0] == TokenType.MNEMONIC){
				
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						int addr = symbolTable.getEQUValue(token.toString());
						
						if((addr >= 0) && (addr <= MAX_16BIT)){
							intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
							parseEndOfLine(sourceLine, t, token, type);
						}
						else{
							//nfe invalid addr. too large
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 97);
						}
					}
					else{
						//nfe exp EQU or integer value
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 92);
					}
				}
				else{
					//nfe symbol not defined
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 17);
				}
			}
			else if(type[0] == TokenType.DATA){
				try{
					int addr = Integer.parseInt(token.toString());
					if((addr >= 0) && (addr <= MAX_16BIT)){
						intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
						parseEndOfLine(sourceLine, t, token, type);
					}
					else{
						//nfe invalid addr. too large
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 97);
					}
				} catch(NumberFormatException nfe){
					//nfe exp valid int or equ value
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
				}
			}
			else if (token.charAt(0) == ':') {
				// comment, missing operand
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 94);
			}
			else if ((token.toString().compareTo("+") == 0) || (token.toString().compareTo("-") == 0)) {
				// began with + or -
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 100);
			}
			else {
				// token is not a number or a symbol
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 11);
			}
		}
		else {
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
	}
	
	/**
	 * Parses operand field for DUMP.<br>
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Meghan Day
	 * 
	 * Change Log:<br>
	 *  - 05/17/09 - Meghan Day<br>
	 *  	- Created and filled in method.
	 */
	private static void parseOperandsDUMP(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, int[] locationCounter) {
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 2);
			
			if(type[0] == TokenType.MNEMONIC){
				
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						int addr = symbolTable.getEQUValue(token.toString());
						
						if((addr >= 1) && (addr <= 3)){
							intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
							parseEndOfLine(sourceLine, t, token, type);
						}
						else{
							//nfe invalid addr. too large
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 98);
						}
					}
					else{
						//nfe symbol not equated
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 92);
					}
				}
				else{
					//nfe symbol not defined
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 17);
				}
			}
			else if(type[0] == TokenType.DATA){
				try{
					int addr = Integer.parseInt(token.toString());
					if((addr >= 1) && (addr <= 3)){
						intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
						parseEndOfLine(sourceLine, t, token, type);
					}
					else{
						//nfe invalid addr. too large
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 98);
					}
				} catch(NumberFormatException nfe){
					//nfe exp valid int or equ value
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
				}
			}
			else if (token.charAt(0) == ':') {
				// comment, missing operand
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 94);
			}
			else {
				// token is not a number or a symbol
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 11);
			}
		}
		else {
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
	}
	
	/**
	 * Parses operand field for PWR.<br>
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @author Meghan Day
	 * 
	 * Change Log:<br>
	 *  - 05/17/09 - Meghan Day<br>
	 *  	- Created and filled in method.
	 */
	private static void parseOperandsPWR(Tokenizer t, StringBuffer sourceLine,
			StringBuffer token, TokenType[] type, int[] locationCounter) {
		if(sourceLine.length() > 0){
			t.getNextToken(sourceLine, token, type);
			intermediateVersion.updateAddrFlag(intermediateVersion.length() - 1, 2);
			
			if(type[0] == TokenType.MNEMONIC){
				
				if(symbolTable.symbolIsDefined(token.toString())){
					
					if(symbolTable.getUsage(token.toString()) == SymbolUsage.EQU_VALUE){
						int addr = symbolTable.getEQUValue(token.toString());
						
						if((addr >= 0) && (addr <= 10)){
							intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
							parseEndOfLine(sourceLine, t, token, type);
						}
						else{
							//nfe invalid addr. too large
							intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
							intermediateVersion.addError(intermediateVersion.length() - 1, 99);
						}
					}
					else{
						//nfe exp EQU or integer value
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 92);
					}
				}
				else{
					//nfe symbol not defined
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 17);
				}
			}
			else if(type[0] == TokenType.DATA){
				try{
					int addr = Integer.parseInt(token.toString());
					if((addr >= 0) && (addr <= 10)){
						intermediateVersion.updateAddr(intermediateVersion.length() - 1, addr);
						parseEndOfLine(sourceLine, t, token, type);
					}
					else{
						//nfe invalid addr. too large
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 99);
					}
				} catch(NumberFormatException nfe){
					//nfe exp valid int or equ value
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 11);
				}
			}
			else if (token.charAt(0) == ':') {
				// comment, missing operand
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 94);
			}
			else {
				// token is not a number or a symbol
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 11);
			}
		}
		else {
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
		}
	}


	/**
     * After an whitespace has been detected on the first line, this method attempts to identify a valid instruction as either
     * a machine op or assembler directive. This will use the information in the MachineOpsTable and DirectivesTable to determine
     * how to handle the location counter, incomming labels and errors. This method calls through to parseOperands() with the 
     * instruction's operand_code to allow the instructions operands to be parsed. This method also completely parses the "FINISH"
     * instruction as a sort of 'base case'.
     *  
     * Change Log:<br>
     * 	- 04/17/09 - Tobin Chee<br>
     *  	- Added symb parameter to allow program to check if labels are allowed with specific instructions.<br>
     *  	- Added calls to check if labels are allowed with specific instructions.<br><br>
     * 	- 05/05/09 - Tobin Chee<br>
     *  	- Changed conditional statement to check for "FINSH instead of  "FINISH" to match proper CSE7000 specifications.<br><br>
     *  - 05/17/09 - Tobin Chee<br>
     *  	- Updated documentation
     * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @param hasLabel True if the instruction has a label, false if otherwise.
	 * @param symb The label to be added to the symbol, if there is a label.  See hasLabel.
     * @return SourceProgramStatus.NORMAL for no error and non-fatal errors<br>
     * SourceProgramStatus.FATAL_ERROR for fatal error found.
     * @author Tobin Chee
     */
    private static SourceProgramStatus parseInstruction(Tokenizer t, StringBuffer sourceLine, StringBuffer token, TokenType[] type, int[] locationCounter, boolean hasLabel, Symbol symb){
    	
	    token = new StringBuffer(token.toString().toUpperCase());
	    
	    if(machineOps.containsOp(token.toString())){
	        intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode(token.toString()));
            intermediateVersion.setConsumesMemory(intermediateVersion.length() - 1, true);
	        
            if(locationCounter[0] <= MAX_PROGRAM_LENGTH){ //if in valid range
		        if((PRMLSTcount > 0) && (token.toString().compareTo("PRMLST") != 0)){ //if expecting PRMLST and PRMLST not found
		        	//nfe exp PRMLST instruction, attempt to parse instruction anyway.
		        	String PRMIDLabel = symbolTable.getPRMIDLabel();
		        	int EQUVal = symbolTable.getEQUValue(PRMIDLabel) - PRMLSTcount;
		        	symbolTable.updateEQUValue(PRMIDLabel, EQUVal);
		        	PRMLSTcount = 0;
		        	intermediateVersion.addError(intermediateVersion.length() - 1, 51);
		        }
		        else{
		        	//do nothing, completely normal
		        }
		        
		        if(hasLabel){
	                symbolTable.defineSymbol(symb);
	                parseOperands(t, sourceLine, token, type, locationCounter, machineOps.getOperandType(token.toString()));
	                locationCounter[0]++;
	                return SourceProgramStatus.NORMAL;
		        }
		        else{
	                parseOperands(t, sourceLine, token, type, locationCounter, machineOps.getOperandType(token.toString()));
	                locationCounter[0]++;
	                return SourceProgramStatus.NORMAL;
		        }
            }
            else{ //if program overflows, log on the line that consumes the memory
    			intermediateVersion.addError(intermediateVersion.length() - 1, 26);
                return SourceProgramStatus.FATAL_ERROR;
            }
	    }
	    else if (directives.containsDirective(token.toString())){
	    	if(token.toString().compareTo("BEGIN") != 0){
		        boolean consumesMemory = directives.consumesMemory(token.toString().toUpperCase());
		        if(hasLabel){
		            
		            if(directives.isLabelAllowed(token.toString()) != LabelAllowed.NOT_ALLOWED){
		            	symbolTable.defineSymbol(symb);
		            }
		            else{
		                //NFE label not allowed with current directive
		            	intermediateVersion.addError(intermediateVersion.length() - 1, 20);
		            }
		            
		            if(token.toString().toUpperCase().compareTo("FINSH") == 0){
		                parseEndOfLine(sourceLine, t, token, type);
		                return SourceProgramStatus.END_OF_PROGRAM;
		            }
		            else{
		                //do NOT "look-ahead" before the parseOperands() call
		                if(consumesMemory){
		                    intermediateVersion.setConsumesMemory(intermediateVersion.length() - 1, true);
		                    
		                	if(locationCounter[0] <= MAX_PROGRAM_LENGTH){
			                	if((PRMLSTcount > 0) && (token.toString().compareTo("PRMLST") != 0)){
			        	        	//nfe exp PRMLST instruction, attempt to parse instruction anyway.
			        	        	String PRMIDLabel = symbolTable.getPRMIDLabel();
			        	        	int EQUVal = symbolTable.getEQUValue(PRMIDLabel) - PRMLSTcount;
			        	        	symbolTable.updateEQUValue(PRMIDLabel, EQUVal);
			        	        	PRMLSTcount = 0;
			        	        	intermediateVersion.addError(intermediateVersion.length() - 1, 51);
			        	        }
			        	        else{
			        	        	//do nothing, completely normal
			        	        }
				                parseOperands(t, sourceLine, token, type, locationCounter, directives.getOperandType(token.toString()));
			                    locationCounter[0]++;
		                	}
		                	else{ //if program overflows, log on the line that consumes the memory
	                			intermediateVersion.addError(intermediateVersion.length() - 1, 26);
	                            return SourceProgramStatus.FATAL_ERROR;
		                	}
		                }
		                else{ //if !consumesMemory
			                parseOperands(t, sourceLine, token, type, locationCounter, directives.getOperandType(token.toString()));
		                }
		                return SourceProgramStatus.NORMAL;
		            }       
		        }
		        else if(directives.isLabelAllowed(token.toString()) == LabelAllowed.REQUIRED){
		            //NFE label required for current instruction
		            if(consumesMemory){
	                    intermediateVersion.setConsumesMemory(intermediateVersion.length() - 1, true);
	                    if(locationCounter[0] <= MAX_PROGRAM_LENGTH){
			            	intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			            	intermediateVersion.addError(intermediateVersion.length() - 1, 36);
			            	locationCounter[0]++;
	                	}
	                	else{ //if program overflows, log on the line that consumes the memory
                			intermediateVersion.addError(intermediateVersion.length() - 1, 26);
                            return SourceProgramStatus.FATAL_ERROR;
	                	}
		            }
		            else{
	                    //log error, but no mem impact = no NOP
		            	intermediateVersion.addError(intermediateVersion.length() - 1, 36);
		            }
		            return SourceProgramStatus.NORMAL;
		        }
		        else{
		            //do NOT "look-ahead" before the parseOperands() call
		            if(token.toString().toUpperCase().compareTo("FINSH") == 0){
		                parseEndOfLine(sourceLine, t, token, type);
		                return SourceProgramStatus.END_OF_PROGRAM;
		            }
		            else{
		            	if(consumesMemory){
		                    intermediateVersion.setConsumesMemory(intermediateVersion.length() - 1, true);
		            		
		                    if(locationCounter[0] <= MAX_PROGRAM_LENGTH){
			        	        if((PRMLSTcount > 0) && (token.toString().compareTo("PRMLST") != 0)){
			        	        	//nfe exp PRMLST instruction, attempt to parse instruction anyway.
			        	        	String PRMIDLabel = symbolTable.getPRMIDLabel();
			        	        	int EQUVal = symbolTable.getEQUValue(PRMIDLabel) - PRMLSTcount;
			        	        	symbolTable.updateEQUValue(PRMIDLabel, EQUVal);
			        	        	PRMLSTcount = 0;
			        	        	intermediateVersion.addError(intermediateVersion.length() - 1, 51);
			        	        }
			        	        else{
			        	        	//do nothing, completely normal
			        	        }
				                parseOperands(t, sourceLine, token, type, locationCounter, directives.getOperandType(token.toString()));
			                    locationCounter[0]++;
		                	}
		                	else{ //if program overflows, log on the line that consumes the memory
	                			intermediateVersion.addError(intermediateVersion.length() - 1, 26);
	                            return SourceProgramStatus.FATAL_ERROR;
		                	}
		                }
		                else{ //if !consumesMemory
			                parseOperands(t, sourceLine, token, type, locationCounter, directives.getOperandType(token.toString()));
		                }
		                return SourceProgramStatus.NORMAL;
		            }
		        }

		    }
		    else{
		    	//nfe cannot invoke the directive BEGIN twice in one program.
	        	intermediateVersion.addError(intermediateVersion.length() - 1, 58);
	        	return SourceProgramStatus.NORMAL;
		    }
	    }
	    else{
	    	//nfe exp operation or directive, NOP b/c it sort of looks like this was an attempt at an instruction
            intermediateVersion.setConsumesMemory(intermediateVersion.length() - 1, true);
        	intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));//when in doubt NOP
        	locationCounter[0]++;
        	intermediateVersion.addError(intermediateVersion.length() - 1, 37);
	        return SourceProgramStatus.NORMAL;
	    }
    }



	/**
	 * On a new line of code, if a string is detected as the first token this method will be called to 
	 * handle and potential labels. This method creates new symbol objects based on what that first string is
	 * and passes them on to parseInstruction() to have them defined if the instruction permits a label. This
	 * method deals with the problem of duplicate labels and will ignore a duplicate label and try to continue parsing.
	 * However, later if the instruction requires a label, and the label has been ignored there will be a SEVERE error.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
	 * @return NORMAL, if the program has encountered normal code or a non-fatal error<br>
	 *         END_OF_PROGRAM, if called methods encounter the instruction "FINISH"<br>
	 *         FATAL_ERROR, if the called methods encounter a fatal error
	 * @author Tobin Chee
	 *         
	 * Change Log:<br>
	 * 	- 05/06/09 - Tobin Chee<br>
	 * 		- Moved some code from this method to the submethod parseLabelSub to make code more compact<br><br>
	 * 	- 05/17/09 - Tobin Chee<br>
	 * 		- Commmented out code that was causing the program to overwrite AVERTed symbols
	 */
	private static SourceProgramStatus parseLabel(Tokenizer t,
			StringBuffer sourceLine, StringBuffer token, TokenType[] type,
			int[] locationCounter) {
		
		Symbol symb = new Symbol();
		
		if (!symbolTable.symbolIsDefined(token.toString())) { //if not defined
			symb.setLabel(token.toString());
			return parseLabelSub(t, sourceLine, token, type, locationCounter, true, symb);
		}
		else if((symbolTable.getUsage(token.toString()) == SymbolUsage.AVERT)){ //if defined and AVERT
			
			if(symbolTable.getLocation(token.toString()) == -1){
				symb.setLabel(token.toString());
				symb.setLocation(locationCounter[0]);
				symb.setUsage(symbolTable.getUsage(token.toString()));
				return parseLabelSub(t, sourceLine, token, type, locationCounter, true, symb);
			}
			else{
				//nfe duplicate label
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 31);
				return SourceProgramStatus.NORMAL;
			}
		}
		else {
			// ERROR - potentially non-fatal, duplicate label
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 31);
			return parseLabelSub(t, sourceLine, token, type, locationCounter, false, symb);
			//return SourceProgramStatus.NORMAL;
		}
	}
	
	/** This method is called multiple times by parseLabel(). It deals with the code after the
	 * label + WHITEPSACE.
	 * 
	 * @param t Tokenizer to be used to extract tokens.
	 * @param sourceLine The portion of the line of code containing the operand, no leading spaces.
	 * @param token Variable to be used to get tokens.
	 * @param type TokenType variable to be used to store type of most recent token.
	 * @param locationCounter Counter of current location.
 	 * @param hasLabel True if the instruction has a label, false if otherwise.
	 * @param symb The label to be added to the symbol, if there is a label.  See hasLabel.
	 * @return true, if the parser has encountered the end of the program "FINISH"<br>
	 *         false, otherwise
	 * @author Tobin Chee
	 *  
	 * Change Log:<br>
	 * 	- 05/15/09 - Tobin Chee<br>
	 * 		- Replaced "magic numbers" with MAX_16BIT and MIN_16BIT
	 */
	private static SourceProgramStatus parseLabelSub(Tokenizer t,
			StringBuffer sourceLine, StringBuffer token, TokenType[] type,
			int[] locationCounter, boolean hasLabel, Symbol symb) {

		if (sourceLine.length() > 0) {
			t.getNextToken(sourceLine, token, type);

			if (type[0] == TokenType.WHITESPACE) {

				if (sourceLine.length() > 0) {
					t.getNextToken(sourceLine, token, type);

					if (type[0] == TokenType.MNEMONIC) {

						if(hasLabel){
							if (token.toString().toUpperCase().compareTo("EQU") == 0) {
								//symb.setLocation(-1); // -1 denotes no location, removed call b/c it defaults to -1 anyway 
								symb.setUsage(SymbolUsage.EQU_VALUE);
								
								if (sourceLine.length() > 0) {
									t.getNextToken(sourceLine, token, type);
	
									if (type[0] == TokenType.WHITESPACE) {
	
										try{
											int result = Integer.parseInt(parseOperandsEQU(t, sourceLine, token, type, locationCounter));
											
											if((result <= MAX_16BIT) &&
													(result >= MIN_16BIT)){
												symb.setEquValue(result);
												symbolTable.defineSymbol(symb);
												return SourceProgramStatus.NORMAL;
											}
											else{
												//nfe EQU value too large
												intermediateVersion.addError(intermediateVersion.length() - 1, 13);
												return SourceProgramStatus.NORMAL;
											}
										} catch (NumberFormatException nfe){
											//Do nothing, the errors have already been logged by parseOperandsEQU
											return SourceProgramStatus.NORMAL;
										}
									}
									else {
										// ERROR - expecting whitespace token after Directive
										intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
										intermediateVersion.addError(intermediateVersion.length() - 1, 23);
										return SourceProgramStatus.NORMAL;
									}
								}
								else {
									// NFE unex EOL
									intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
									intermediateVersion.addError(intermediateVersion.length() - 1, 1);
									return SourceProgramStatus.NORMAL;
								}
							}
							else if(type[0] == TokenType.COMMENT){
								//nfe comment cannot follow a label
								intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(intermediateVersion.length() - 1, 27);
								return SourceProgramStatus.NORMAL;
							}
							else {
								symb.setLocation(locationCounter[0]);
								return parseInstruction(t, sourceLine, token,type, locationCounter, true, symb);
							}
						}
						else{ //if no label
							symb.setLocation(locationCounter[0]);
							symb.setUsage(SymbolUsage.DATA_LABEL);
							return parseInstruction(t, sourceLine, token,type, locationCounter, false, symb);
						}
					}
					else {
						// NFE exp operation after label
						intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
						intermediateVersion.addError(intermediateVersion.length() - 1, 29);
						return SourceProgramStatus.NORMAL;
					}
				}
				else {
					// NFE unex EOL
					intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
					intermediateVersion.addError(intermediateVersion.length() - 1, 29);
					return SourceProgramStatus.NORMAL;
				}
			}
			else {
				// What if type == COMMENT? do we care? I think the parser
				// will run a label right into a comment and pop give a type
				// error
				// ERROR - NF - expecting whitespace after label
				intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
				intermediateVersion.addError(intermediateVersion.length() - 1, 30);
				return SourceProgramStatus.NORMAL;
			}
		}
		else {
			// ERROR - pot. non-fatal - unexpected end of line.
			intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
			return SourceProgramStatus.NORMAL;
		}
	}
	
	/** Parse the rest of the program
     * After the first line has been read (as the base case) this will be the generic 
     * parser that parses the rest of the program. This program will call other parse 
     * methods, such as parseComment() or parseSymbol() to keep the code neat.<br><br>
     *
     * Change Log:<br>
     *	- 04/13/09 - Tobin Chee<br>
     * 		- Filled in most the code.<br>
     * 		- Added some code and comments to handle end of program.<br><br>
     *  - 05/04/09 - Tobin Chee<br>
     *  	- Method now attempts to parse instructions and comments after an invalid label<br>
     *  	- Commented out unnecessary error logging.
     *  
     * @param in The file input stream containing the rest of the program's code.
	 * @param t Tokenizer to be used to extract tokens.
	 * @param locationCounter Counter of current location.
	 * @author Tobin Chee
     */
    private static void parseRest(BufferedReader in, Tokenizer t, int[] locationCounter){
            try{
	                String sourceLineBuffer = "";
	                StringBuffer sourceLine = new StringBuffer();
	                StringBuffer token = new StringBuffer();
	                TokenType[] type = {TokenType.COMMENT}; //arbitrary default value
	                SourceProgramStatus status = SourceProgramStatus.NORMAL;
	
	
	                sourceLineBuffer = in.readLine();
	               
	                while((sourceLineBuffer != null) && (status == SourceProgramStatus.NORMAL)){
	                	
	                	if(locationCounter[0] <= MAX_PROGRAM_LENGTH){}
	                	if(sourceLine.length() > MAX_LINE_LENGTH){
	                    	//nfe warning source line too large, reduce to 100 and warn user
	                        sourceLine = new StringBuffer(sourceLine.substring(0, 100));
	                    	intermediateVersion.addError(intermediateVersion.length() - 1, 34);
	                    }
                        intermediateVersion.addEntry();
                        intermediateVersion.updateSourceLine(intermediateVersion.length() - 1, sourceLineBuffer);
                        intermediateVersion.updateLocationCounter(intermediateVersion.length() - 1, locationCounter[0]);
                        
//                        if(locationCounter[0] > MAX_PROGRAM_LENGTH){ // > 4095
//                            //DEFINE ERROR IN intermediateVersion - FE LC must be <= MAX_PROGRAM_LENGTH (0 indexed)
//                			intermediateVersion.addError(intermediateVersion.length() - 1, 26);
//                            status = SourceProgramStatus.FATAL_ERROR;
//                        }
//                        else{
                        sourceLine = new StringBuffer(sourceLineBuffer);
                        if(sourceLine.length() > 0){
                            t.getNextToken(sourceLine, token, type);
                           
                            if(type[0] == TokenType.WHITESPACE){
                               
                                if(sourceLine.length() > 0){ //no label
                                    t.getNextToken(sourceLine, token, type);
                                    if(type[0] == TokenType.COMMENT){
                                    	//nfe comments must start the line or come after an Instruction/Directive
                                    	//Not incrementing lc or logging "NOP" b/c this is an error, but we assume the users intent was just to have a comment (ie non-memory consuming)
                            			intermediateVersion.addError(intermediateVersion.length() - 1, 27);
                                    }
                                    else{
                                    	status = parseInstruction(t, sourceLine, token, type, locationCounter, false, new Symbol());
                                    }
                                }
                                else{
                                	//nfe unex EOL
            	                    intermediateVersion.setConsumesMemory(intermediateVersion.length() - 1, true);
                                	intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
                                	locationCounter[0]++;
                        			intermediateVersion.addError(intermediateVersion.length() - 1, 1);
                                }
                            }
                            else if(type[0] == TokenType.COMMENT){
                            	//Do nothing, its okay to have a comment start a line.
                            }
                            else if(type[0] == TokenType.MNEMONIC){
                        		status = parseLabel(t, sourceLine, token, type, locationCounter);
                            }
                            else if(type[0] == TokenType.ERROR){
                            	//assuming this an invalid attempt an a label
                    			intermediateVersion.addError(intermediateVersion.length() - 1, 53);
                    			
                            	if(sourceLine.length() > 0){
                            		t.getNextToken(sourceLine, token, type);
                            		
                            		if(type[0] == TokenType.WHITESPACE){
                            			
                            			if(sourceLine.length() > 0){
                            				t.getNextToken(sourceLine, token, type);
                            				
                            				if(type[0] == TokenType.MNEMONIC){
                            					status = parseInstruction(t, sourceLine, token, type, locationCounter, false, new Symbol());
                            				}
                            				else if(type[0] == TokenType.COMMENT){
                            					//nfe comment must either begin the line or end the line
                            		        	intermediateVersion.addError(intermediateVersion.length() - 1, 27);
                            				}
                            				else{
                            					//nfe exp instruction
                            		        	intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));//when in doubt NOP
                            		        	locationCounter[0]++;
                            		        	intermediateVersion.addError(intermediateVersion.length() - 1, 37);
                            				}
                            			}
                            			else{
                            				//DON'T NOP, because a label followed by nothing should not take memory
                            				//nfe unex EOL
                            				intermediateVersion.addError(intermediateVersion.length() - 1, 1);
                            			}
                            		}
                            		else{
                            			//NOP b/c its impossible to determine if a line says "lbl,ADD =20" or if it says "lbl, :hi there" in this case, if in doubt, NOP
                            			//TODO nfe expecting whitespace to separate label and instruction field
                    		        	intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));//when in doubt NOP
                    		        	locationCounter[0]++;
                            			intermediateVersion.addError(intermediateVersion.length() - 1, 30);
                            		}
                            	}
                            }
                            else{
                            	intermediateVersion.updateOpCode(intermediateVersion.length() - 1, machineOps.getHexCode("NOP"));
                            	locationCounter[0]++;
                            	intermediateVersion.addError(intermediateVersion.length() - 1, 43);
                            }
                        }
                        else{
                        	//nfe warning empty line of code, no NOP or increment LC because it is a blank line.
            				intermediateVersion.addError(intermediateVersion.length() - 1, 44);
                        	
                        }
                        
                        if(locationCounter[0] > (MAX_PROGRAM_LENGTH + 1)){
                        	//fatal error, program has exceeded 4096 words of memory
                        	intermediateVersion.addError(intermediateVersion.length() - 1, 26);
                        	intermediateVersion.setContainsFatalError(true);
                        	status = SourceProgramStatus.FATAL_ERROR;
                        }
                        sourceLineBuffer = in.readLine();
//                        }
                    }
                   
                    if(status == SourceProgramStatus.FATAL_ERROR){
                    	//fatal error has been detected during parsing, terminate pass 1 (do nothing)
                    	intermediateVersion.setContainsFatalError(true);
                    	System.out.println("ERROR: Fatal error encountered during pass 1. Pass 1 has been terminated.");
                    }
                    else if((sourceLineBuffer == null) && (status == SourceProgramStatus.END_OF_PROGRAM)){
                    	//No error, normal end of program. terminate pass1 (do nothing)
                    }
                    else if(sourceLineBuffer == null){ //if eof, but havent reached finish yet, fatal error
                    	intermediateVersion.addError(intermediateVersion.length() - 1, 0);
                    	intermediateVersion.setContainsFatalError(true);
                    }
                    else{ //if endOfProgram but there are more lines, warning
                    	intermediateVersion.addError(intermediateVersion.length() - 1, 3);
                    	//Terminate pass1 (do nothing)
                    }
            } catch(IOException ioe){
                    System.out.println("Assembler Error: problem reading from file");
            }
           
           
    }
    
    /** This method is for debugging purposes only.
     * 
     * A slightly modified version of the user report for debugging purposes only.
     * Outputs the 32-bit instruction code in sectioned binary for easy debugging, as well as 
     * everything else that the user report contains.
     * 
     * @param debugFile file to which this method writes.
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- No changes
     */
    private static void putDebugReportToFile(BufferedWriter debugFile){
    	
    	try{
    		//Header
    		debugFile.write("LOC\tOBJ CODE\tOBJ CODE\t\t\t\t\t\tA/R/C\tSTMT\tSOURCE STATEMENT\n");
    		debugFile.write("(HEX)\t(HEX)\t\t(BIN)\t\t\t\t\t\t\t\t\t(DEC)\n");
    		
    		//Body
    		for(int i = 0; i < intermediateVersion.length(); i++){
    			//LOC (HEX)
    			debugFile.write(Integer.toHexString(intermediateVersion.getLocationCounter(i)) + "\t");
    			//OBJ CODE (HEX)
    			//A/R/C
    			if(intermediateVersion.getConsumesMemory(i)){
    				//instruction takes up memory and isn't BEGIN or last line of program
    				StringBuffer hexInstruction = new StringBuffer(Integer.toHexString(intermediateVersion.getInstructionCode(i)));
    				StringBuffer binInstruction = new StringBuffer(Integer.toBinaryString(intermediateVersion.getInstructionCode(i)));
    				
    				while(hexInstruction.length() < 8){
    					hexInstruction.insert(0, "0");
    				}
        			debugFile.write(hexInstruction + "\t");
        			
        			while(binInstruction.length() < 32){
        				binInstruction.insert(0, "0");
        			}
        			debugFile.write(binInstruction.substring(0, 8) + " ");
        			debugFile.write(binInstruction.substring(8, 11) + " ");
        			debugFile.write(binInstruction.substring(11, 12) + " ");
        			debugFile.write(binInstruction.substring(12, 14) + " ");
        			debugFile.write(binInstruction.substring(14, 16) + " ");
        			debugFile.write(binInstruction.substring(16, 32) + "\t");
        			
        			debugFile.write(intermediateVersion.getARCFlag(i) + "\t");
    			}
    			else{
    				//instruction doesn't take up memory
    				debugFile.write("--------\t");
    				debugFile.write("-------- --- - -- -- ---------------\t");
    				debugFile.write("-\t");
    			}
    			//STMT (DEC)
    			//TODO what is the STMT in dec??? Is this the line of code in source file? Fix this if need be
    			debugFile.write(i + "\t");
    			//SOURCE STATEMENT
    			debugFile.write(intermediateVersion.getSourceLine(i) + "\n");
    			for(int x :intermediateVersion.getErrors(i)){
    				debugFile.write("\terror:" + errors.getErrorSeverity(x).toString() + ": " + errors.getErrorDescription(x) + "\n");
    			}
    		}
    		
    	} catch(IOException ioe){
    		System.out.println("ERROR: Problem writing user report to file");
    	}
    	putSymbolTableToFile(debugFile);
    }

	/** Run the assembler.<br>
     * This method will validate the input stream and output stream given at the command 
     * line. If either of these are invalid it will print an error to the command line.<br><br>
     * 
     * Change Log:<br>
     *	- 04/06/09 - Tobin Chee<br>
     *  	- Created initial skeleton. Wrote pseudocode and comments.<br>
     *  	- Added validation for commandline args and initialized required IO streams.<br>
     *		- Added calls to populateMachineOps(), populateDirectives(), populateErrors(), pass1(in) and pass2(out).<br><br>
     *	- 04/25/09 - Tobin Chee<br>
     *		- Added additional output statements for the user report.<br><br>
     *	- 05/10/09 - Tobin Chee<br>
     *		- Added additional output statements for debugging purposes.<br>
     *		- Changed the user report file suffix from "intermediate" to "report"
     * 
     * @param args File Names: <br>
     * args[0] is the source file to be compiled (FileName.s)<br>
     * args[1] is the object file to be output (FileName.o)
     * @author Tobin Chee
     */
    public static void main(String[] args){
    	final int NUMBER_OF_ARGS = 2;
    	
    	if(args.length >= NUMBER_OF_ARGS){
	        if(args[0].length() > 2){
			    if((args[0].charAt(args[0].length() - 2) == '.') &&
			            (args[0].charAt(args[0].length() - 1) == 's')){
	                if(args[1].length() > 2){
	                    if((args[1].charAt(args[1].length() - 2) == '.') &&
	                                    (args[1].charAt(args[1].length() - 1) == 'o')){
		                    try{
	                    		File f = new File(args[0]);
	                    		if(f.exists()){
	                                BufferedReader sourceFile = new BufferedReader(new FileReader(args[0]));
	                                BufferedWriter objectFile = new BufferedWriter(new FileWriter(args[1]));
	                                BufferedWriter reportFile;
	                                BufferedWriter debugFile;
	                                String tempFileName;
	                                Integer x = 0;
	                                
	                                tempFileName = args[1].substring(0, args[1].length() - 2) + "-report";
	                                while(new File(tempFileName + x.toString() + ".txt").exists()){
	                                	x++;
	                                }
	                                reportFile = new BufferedWriter(new FileWriter(tempFileName + x.toString() + ".txt"));
	                                
	                                
	                                pass1(sourceFile);
	                                sourceFile.close();
	                        		//TODO remove this: START DEBUG
	                                tempFileName = args[1].substring(0, args[1].length() - 2) + "-DEBUG";
	                                while(new File(tempFileName + x.toString() + ".txt").exists()){
	                                	x++;
	                                }
	                                debugFile = new BufferedWriter(new FileWriter(tempFileName + x.toString() + ".txt"));
	                        		//TODO remove this: END DEBUG
	                                pass2(objectFile, reportFile, debugFile); //TODO debugFile needs to be removed by turn in potentially
	                                debugFile.close();
	                                objectFile.close();
	                                reportFile.close();
	                    		}
	                    		else{
	                    			System.out.println("ERROR: Source file does not exist");
	                    		}
		                    }
		                    catch(IOException ioe){
		                            System.out.println("ERROR: Problem initializing IO streams");
		                    }
	                    }
	                    else{
	                            System.out.println("ERROR: Invalid object file name. File name must end in \".o\"");
	                    }
	                }
	                else{
	                        System.out.println("ERROR: Object file name must be at least 3 characters long");
	                }
		            }
		            else{
		                    System.out.println("ERROR: Invalid source file extension. File name must end in \".s\"");
		            }
	        }
	        else{
	                System.out.println("ERROR: Source file name must be at least 3 characters long");
	        }
    	}
    	else{ //if args.length < NUMBER_OF_ARGS
    		System.out.println("ERROR: Insufficient number of args. Program requires " + NUMBER_OF_ARGS + " to run properly");
    	}
    }


    /** Perform all pass one functions, including putting symbols in a symbol table and 
     * storing the code in an intermediate verson.<br><br>
     * 
     * Change Log:<br>
     * 	- 04/06/09 - Tobin Chee<br>
     *   	- Created initial skeleton.<br><br>
     * 	- 04/13/09 - Tobin Chee<br>
     *  	- Filled in partial code. Handled the base case and made calls to appropriate parseSomething() methods.<br><br>
     * 	- 04/13/09 - Tobin Chee<br>
     *  	- Completely rewrote method to compensate for changes to the way the new Tokenizer works.<br>
     *    	- Method is essentially done, with need for debugging and comments.<br><br>
     *	- 04/16/09 - Tobin Chee<br>
     *		- Location counter changed to a single element array so that it may be passed by reference.<br><br>
     * 	- 04/28/09 - Tobin Chee<br>
     * 		- Updated error output to be more descriptive.<br><br>
     * 	- 05/16/09 - Tobin Chee<br>
     * 		- Replaced magic numbers with MAX_LINE_LENGTH, MAX_PROGRAM_LENGTH and MIN_PROGRAM_LENGTH.
     * 
     * @param in The input stream containing the source code of the program to be assembled.
     * @author Tobin Chee
     */
    public static void pass1(BufferedReader in){
    
	    try{
            Tokenizer t = new SlowTokenizer1();
            String sourceLineBuffer;
            StringBuffer sourceLine;
            StringBuffer token = new StringBuffer();
            TokenType[] type = {TokenType.COMMENT}; //arbitrary initial value
            Symbol symb = new Symbol();
            int[] locationCounter = {0};
            
            sourceLineBuffer = in.readLine();
            
            if((sourceLineBuffer != null)){ //if not end of file
            	sourceLine = new StringBuffer(sourceLineBuffer);
                intermediateVersion.addEntry();
                intermediateVersion.updateSourceLine(intermediateVersion.length() - 1, sourceLine.toString());
                intermediateVersion.updateLocationCounter(intermediateVersion.length() - 1, locationCounter[0]);
                //Consumes memory defaults to false, ne need to set it
                
                if(sourceLine.length() > MAX_LINE_LENGTH){
                	//nfe warning source line too large, reduce to 100 and warn user
                    sourceLine = new StringBuffer(sourceLine.substring(0, 100));
                	intermediateVersion.addError(intermediateVersion.length() - 1, 34);
                }
            
	            if(sourceLine.length() > 0){
	                t.getNextToken(sourceLine, token, type);
	                if(type[0] == TokenType.MNEMONIC){
	                    symb.setLabel(token.toString());
	                    symb.setUsage(SymbolUsage.PROGRAM_NAME);
	                    
	                    if(sourceLine.length() > 0){
	                        t.getNextToken(sourceLine, token, type);
	                        if(type[0] == TokenType.WHITESPACE){
	                                
	                            if(sourceLine.length() > 0){
	                                    t.getNextToken(sourceLine, token, type);
	                                    
	                                if(token.toString().toUpperCase().compareTo("BEGIN") == 0){
	                                        
	                                    if(sourceLine.length() > 0){
	                                        t.getNextToken(sourceLine, token, type);
	                                        
	                                        if(type[0] == TokenType.WHITESPACE){
	                                                
	                                            if(sourceLine.length() > 0){
	                                                t.getNextToken(sourceLine, token, type);
	                                                
	                                                if(type[0] == TokenType.DATA){
	                                                    try{
	                                                        int programStartLocation = Integer.parseInt(token.toString());
	                                                        
	                                                        if(programStartLocation <= MAX_PROGRAM_LENGTH){ //sign's not permitted. No need to check for >= 0
	                                                        	intermediateVersion.setProgramStartLocation(programStartLocation);
	                                                        	locationCounter[0] = programStartLocation;
	                                                        	intermediateVersion.updateLocationCounter(intermediateVersion.length() - 1, locationCounter[0]);
	                                    	                    symb.setLocation(locationCounter[0]);
	                                                            symbolTable.defineSymbol(symb);
	                                                            parseEndOfLine(sourceLine, t, token, type);
	                                                            parseRest(in, t, locationCounter);
	                        	                                System.out.println("Assembler exited as normal");
	                                                        }
	                                                        else{
	                                                            //FATAL ERROR: - initial location counter too large (4096 word limit)
	                                                            System.out.println("FATAL ERROR: program start location is too large (0 <= start_addr <= 4095)");
	                                            	            logFatalBeginError();
	                                                        }
	                                                    } catch(NumberFormatException nfe){
	                                                            //FATAL ERROR: - initial location counter value not a valid integer
	                                                            System.out.println("FATAL ERROR: invalid decimal integer in program start location field");
	                                            	            logFatalBeginError();
	                                                    }
	                                                }
	                                                else{
	                                                    //FE expecting an integer after BEGIN + WHITESPACE
	                                                    System.out.println("FATAL ERROR: expecting decimal integer in program start location field");
	                                    	            logFatalBeginError();
	                                                }
	                                            }
	                                            else{
	                                                //FE unex EOL
	                                                System.out.println("FATAL ERROR: unexpected end of line");
	                                	            logFatalBeginError();
	                                            }
	                                        }
	                                        else{
	                                                //FATAL ERROR:: expecting whitespace after "BEGIN"
	                                                System.out.println("FATAL ERROR: expecting whitespace between BEGIN and program start location");
	                                	            logFatalBeginError();
	                                        }
	                                    }
	                                    else{
	                                            //ERROR: - unexpected end of line. Was expecting WHITESPACE after program label
	                                            System.out.println("FATAL ERROR: unexpected end of line");
	                            	            logFatalBeginError();
	                                    }
	                                }
	                                else{
	                                        //ERROR: - expecting "BEGIN"
	                                        System.out.println("FATAL ERROR: expecting BEGIN in operation field");
	                        	            logFatalBeginError();
	                                }
	                            }
	                            else{
	                                    //ERROR: - unexpected end of line. Was expecting WHITESPACE after program label
	                                    System.out.println("FATAL ERROR: unexpected end of line");
	                    	            logFatalBeginError();
	                            }
	                        }
	                        else{
	                                //ERROR: - expecting whitespace after program label
	                                System.out.println("FATAL ERROR: expecting whitespace after program label");
	                	            logFatalBeginError();
	                        }
	                    }
	                    else{
	                            //ERROR: - unexpected end of line. Was expecting WHITESPACE after program label
	                            System.out.println("FATAL ERROR: unexpected end of line");
	            	            logFatalBeginError();
	                    }
	                }
	                else{
	                        //ERROR: - expecting SYMBOl (program label) to be the first token
	                        System.out.println("FATAL ERROR: first line of the program must start with a label");
	        	            logFatalBeginError();
	                }
	            }
	            else{
	            	System.out.println("FATAL ERROR: first line is empty. Must contain a valid BEGIN instruction");
		            logFatalBeginError();
	            }
            }
            else{
                    //FATAL ERROR: - Empty source file
                    System.out.println("FATAL ERROR: empty source file");
    	            logFatalBeginError();
            }
	    } catch(IOException IOE){
	            //Error reading from file
	            System.out.println("FATAL ERROR: problem reading from file");
	            logFatalBeginError();
	    }              
    }
    
    /**
     * A very simple method that logs a fatal error if one is detected when parsing the
     * first line of the program. Used only to make code more compact.
     */
    public static void logFatalBeginError(){
    	intermediateVersion.addEntry();
    	intermediateVersion.addError(intermediateVersion.length() - 1, 63);
    	intermediateVersion.setContainsFatalError(true);
    }
    
    /**
     * Writes the sorted formatted symbolTable to the reportFile.
     * 
     * @param reportFile the file this method writes to.
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- No changes
     */
    public static void putSymbolTableToFile(BufferedWriter reportFile){
    	/*
    	 * This was going to be implemented outside of symbolTable in proper object
    	 * oriented style, but unfortunately the internal rep supports intuitive
    	 * iteration, so doing it externally is considerably more difficult and
    	 * time consuming.
    	 */
    	symbolTable.sort();
    	symbolTable.putToFile(reportFile);
    }
    
    /**
     * Writes the intermediate version portion of the user report to file.
     * 
     * @param reportFile the file this method writes to.
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- 05/12/09 - Tobin Chee<br>
     * 		- Adjusted formatting to accomodate variable length entries in the user report.
     */
    public static void putIntermediateVersionToFile(BufferedWriter reportFile){
    	//TODO Fill in
    	//TODO update parsing to log whether an instruction takes memory or not
    	//TODO update method to output errors after each line
    	
    	try{
    		//Header
    		reportFile.write("LOC\tOBJ CODE\tA/R/C\tSTMT\tSOURCE STATEMENT\n");
    		reportFile.write("(HEX)\t(HEX)\t\t\t(DEC)\n");
    		
    		//Body
    		for(int i = 0; i < intermediateVersion.length(); i++){
    			//LOC (HEX)
    			reportFile.write(Integer.toHexString(intermediateVersion.getLocationCounter(i)) + "\t");
    			//OBJ CODE (HEX)
    			//A/R/C
    			if(intermediateVersion.getConsumesMemory(i)){
    				//instruction takes up memory and isn't BEGIN or last line of program
    				StringBuffer hexInstruction = new StringBuffer(Integer.toHexString(intermediateVersion.getInstructionCode(i)));
    				
    				while(hexInstruction.length() < 8){
    					hexInstruction.insert(0, "0");
    				}
        			reportFile.write(hexInstruction + "\t");
        			reportFile.write(intermediateVersion.getARCFlag(i) + "\t");
    			}
    			else{
    				//instruction doesn't take up memory
    				reportFile.write("--------\t");
    				reportFile.write("-\t");
    			}
    			//STMT (DEC)
    			//TODO what is the STMT in dec??? Is this the line of code in source file? Fix this if need be
    			reportFile.write(i + "\t");
    			//SOURCE STATEMENT
    			reportFile.write(intermediateVersion.getSourceLine(i) + "\n");
    			for(int x :intermediateVersion.getErrors(i)){
    				reportFile.write("\terror:" + errors.getErrorSeverity(x).toString() + ": " + errors.getErrorDescription(x) + "\n");
    			}
    		}
    		
    	} catch(IOException ioe){
    		System.out.println("ERROR: Problem writing user report to file");
    	}
    }
    
    /**
     * Writes the user report using the static and dynamic tables constructed by pass1.
     * Report file is formatted as defined in Appendix E in the lab manual.
     * 
     * @param reportFile the file this method writes to.
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- 05/02/09 - Tobin Chee<br>
     * 		- Changed method calls to match the updated output methods.<br>
     * 		- Commented out the old calls.
     */
    public static void putReportToFile(BufferedWriter reportFile){
    	//TODO needs to be changed to fit proper formate defined in Appendix E
    	try{
    		putIntermediateVersionToFile(reportFile);
    		reportFile.write("\n");
    		putSymbolTableToFile(reportFile);
    		
    		/*
    		intermediateVersion.putToFile(reportFile);
    		reportFile.write("\n");
    		symbolTable.putToFile(reportFile);
    		*/
    	}
    	catch(IOException ioe){
    		System.out.println("ERROR: problem writing user report to file.");
    	}
    }
    
    /**
     * Writes the header record for the object file, formatted as defined in Appendix C in the lab manual.
     * 
     * @param objectFile the file this method writes to.
     * @return int number of records this method writes to the object file.
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- 05/09/09 - Sam Jones<br>
     * 		- Created file<br><br>
     * 	- 05/10/09 - Tobin Chee<br>
     * 		- Fixed improperly formatted hex code and updated error message.<br><br>
     *  - 05/11/09 - Sam Jones<br>
     *  	- Fixed fields after asking al about confusion.<br><br>
     *  - 06/01/09 - Tobin Chee<br>
     *  	- Changed program length field to not include those words skipped by BEGIN.
     */
    public static int putHeaderRecord(BufferedWriter objectFile){
    	try {
    		// H | Module Name |
    		objectFile.append("H|" + symbolTable.getProgramName() + "|");
    		
    		// Date yyyy:ddd | Time HH:mm:ss |
    		Date todaysDate = new Date();
    		SimpleDateFormat dateNow = new SimpleDateFormat("yyyy:DDD|HH:mm:ss");
    		objectFile.append(dateNow.format(todaysDate) + "|");
    		
    		// Program length hhhh |	
    		objectFile.append(Integer.toHexString(intermediateVersion.getLocationCounter(intermediateVersion.length() - 1) - intermediateVersion.getLocationCounter(0)) + "|");
    		
    		// Assembler Assigned program load address hhhh |
    		objectFile.append(Integer.toHexString(intermediateVersion.getProgramStartLocation()) + "|");
    		
    		// Number of linking record hhhh |
    		int numLinkRec = 1; //always one for the program name
    		for(int i = 0; i < symbolTable.length(); i++) {
    			if (symbolTable.getUsage(i) == SymbolUsage.AVERT) {
    				numLinkRec++;
    			}
    		}
    		objectFile.append(Integer.toHexString(numLinkRec) + "|");
    		
    		// Number of text record hhhh |
    		int numTextRec = 0;
    		for (int i = 0; i < intermediateVersion.length(); i++) {
    			if (intermediateVersion.getConsumesMemory(i)) {
    				numTextRec++;
    			}
    		}
    		objectFile.append(Integer.toHexString(numTextRec) + "|");
    		
    		// Execution start address hhhh | 
    		objectFile.append(Integer.toHexString(intermediateVersion.getProgramStartLocation()) + "|");
    		
    		// CSE7000 | Version # |
    		objectFile.append("CSE7000|Version " + VERSION_NUMBER + "|");
    		
    		// Revision # |
    		objectFile.append("Revision " + REVISION_NUMBER);
    		objectFile.newLine();
        	return 1; // 1 per assembly
    	} catch (IOException e) {
    		System.out.println ("Error: Problem writing header record to object file");
    		return -1; //arbitrary error value
    	}
    }
    
    /**
     * Writes the linking record for the object file, formatted as defined in Appendix C in the lab manual.
     * 
     * @param objectFile the file this method writes to.
     * @return int number of records this method writes to the object file.
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- 05/09/09 - Dan Carpenter<br>
     * 		- Created skeleton for procedure<br><br>
     *  - 05/10/09 - Dan Carpenter<br>
     *  	- Filled in skeleton<br><br>
     *  - 05/11/09 - Tobin Chee<br>
     *  	- Rewrote method and commented out erroneous code.
     */
    public static int putLinkingRecord(BufferedWriter objectFile){
    	
    	try{
    		int count = 0;
    		objectFile.write("L|");
    		objectFile.write(symbolTable.getProgramName() + "|");
    		objectFile.write(Integer.toHexString(symbolTable.getLocation(symbolTable.getProgramName())) + "|");
    		objectFile.write(symbolTable.getProgramName() + "\n");
    		count++;
    		
    		for(int i = 0; i < symbolTable.length(); i++){
    			
    			if(symbolTable.getUsage(i) == SymbolUsage.AVERT){
    	    		objectFile.write("L|");
    	    		objectFile.write(symbolTable.getSymbolLabel(i) + "|");
    	    		objectFile.write(Integer.toHexString(symbolTable.getLocation(symbolTable.getSymbolLabel(i))) + "|");
    	    		objectFile.write(symbolTable.getProgramName() + "\n");
    	    		count++;
    			}
    			//else do nothing
    		}
    		return count;
    	} catch(IOException ioe){
    		System.out.println("Error: Problem writing linking record to object file");
    		return -1; //arbitrary error value
    	}
    	
    	/*//TODO Dan
    	String pName = symbolTable.getProgramName();
    	int records = 1;
    	int count = 0;
    	String[] names = symbolTable.getNamesOfUsage(SymbolUsage.AVERT);
    	try {
			objectFile.write("L|" + pName + "|" + symbolTable.getLocation(pName) + "|" + pName + '\n');
			while(count < names.length){
				objectFile.write("L|" + names[count] + "|" + symbolTable.getLocation(names[count]) + "|" + pName + '\n');
				records++;
			}
		} catch (IOException e) {
			System.out.println("Error: Problem outputting object file");
		}
    	return records;
    	*/
    	
    }
    
    /**
     * Returns the arithmetic sign corresponding to the sign.
     * 
     * @param sign Sign enumeration value to be converted to a string.
     * @return "+", for sign = ArithmeticExpression.Sign.POSITIVE<br>
     * "-", for sign = ArithmeticExpression.Sign.NEGATIVE
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- No changes
     */
    private static String getSignSymbol(ArithmeticExpression.Sign sign){
    	if(sign == ArithmeticExpression.Sign.POSITIVE){
    		return "+";
    	}
    	else{ //if NEGATIVE
    		return "-";
    	}
    }
    
    /**
     * Returns the arithmetic symbol corresponding to the operator.
     * 
     * @param operator
     * @return "+", for operator = ArithmeticExpression.ArithmeticOperator.ADD<br>
     * "-", for operator = ArithmeticExpression.ArithmeticOperator.SUBTRACT<br>
     * "*", for operator = ArithmeticExpression.ArithmeticOperator.MULTIPLY<br>
     * "/", for operator = ArithmeticExpression.ArithmeticOperator.DIVIDE
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- No changes
     */
    private static String getArithmeticOperatorSymbol(ArithmeticExpression.ArithmeticOperator operator){
    	if(operator == ArithmeticExpression.ArithmeticOperator.ADD){
    		return "+";
    	}
    	else if(operator == ArithmeticExpression.ArithmeticOperator.SUBTRACT){
    		return "-";
    	}
    	else if(operator == ArithmeticExpression.ArithmeticOperator.MULTIPLY){
    		return "*";
    	}
    	else{ //if DIVIDE
    		return "/";
    	}
    }
    
    /**
     * Writes the text record for the object file, formatted as defined in Appendix C in the lab manual.
     * 
     * @param objectFile the file this method writes to.
     * @return int number of records this method writes to the object file.
     * @author Tobin Chee, Ben Tarney
     * 
     * Change Log:<br>
     * 	- 05/10/09 - Ben Tarney<br>
     * 		- Created outline<br><br>
     * 	- 05/11/09 - Ben Tarney<br>
     * 		- Filled in method<br><br>
     * 	- 05/12/09 - Tobin Chee<br>
     * 		- Updated code to accomodate the new text record format.<br>
     * 		- Fixed an indexing bug with loopCount.<br><br>
     * 	- 06/01/09 - Tobin Chee<br>
     * 		- Changed output so that all hex S fields are padded to 32 bits.
     */
    public static int putTextRecord(BufferedWriter objectFile){
    	String modName = symbolTable.getProgramName();
    	final int S_FIELDS = 4; //number of S fields
    	int count = 0;
    	
    	try{
    		for(int i = 0;i < intermediateVersion.length(); i++){
    			if(intermediateVersion.getConsumesMemory(i)){
    				StringBuffer instructionCode = new StringBuffer(Integer.toHexString(intermediateVersion.getInstructionCode(i)));
    				
    				while(instructionCode.length() < 8){
    					instructionCode.insert(0, "0");
    				}
    				
    				objectFile.append("T|");
    				objectFile.append(Integer.toHexString(intermediateVersion.getLocationCounter(i)) + "|");
    				objectFile.append(instructionCode + "|");
    				
    				//Tobin's code
    				if(intermediateVersion.getOpCode(i) != machineOps.getHexCode("NOP")){ //if not NOP
    					ArithmeticExpression exp = intermediateVersion.getOperandSymbolExpression(i);
    					
    					if((exp.getSymbolLabel(0).compareTo("") != 0) || (exp.getTermMagnitude(0) != -1)){
    						int loopCount = 0;
    						
    						//base case, since first operand doesn't have an operator before it
							objectFile.write(exp.getARCFlag(0) + "|");
							objectFile.write("+|"); //because the one never has an operator in our program
							objectFile.write(getSignSymbol(exp.getTermSign(0)) + "|");
							
							if(exp.getARCFlag(0) == 'C'){
								objectFile.write(exp.getSymbolLabel(0));
							}
							else{
								objectFile.write(Integer.toHexString(exp.getTermMagnitude(0)));
							}
							objectFile.write("|");
							loopCount ++;
							
							//base case
    						while(loopCount < exp.length()){
    							objectFile.write(exp.getARCFlag(loopCount) + "|");
    							objectFile.write(getArithmeticOperatorSymbol(exp.getOperator(loopCount - 1)) + "|");
    							objectFile.write(getSignSymbol(exp.getTermSign(loopCount)) + "|");
    							
    							if(exp.getARCFlag(loopCount) == 'C'){
    								objectFile.write(exp.getSymbolLabel(loopCount));
    							}
    							else{
    								int temp = exp.getTermMagnitude(loopCount);
    								String s = Integer.toHexString(temp);
    								//Padding all S fields to 32-bits for ease of conversion in the linker
									while(s.length() < 8){
										s = "0" + s;
									}
    								objectFile.write(s);
    							}
    							objectFile.write("|");
    							loopCount++;
    						}
    						//output blank fields that the expression didn't use
    						while(loopCount < S_FIELDS){ // S_FIELDS = 4 in this case
    	    					objectFile.append("" + '|'); //ARC flag
    	    					objectFile.append("" + '|' ); //operator + or - or * or / 
    	    					objectFile.append("" + '|'); //sign + / -
    	    					objectFile.append("" + '|'); //external refrence
    							loopCount++;
    						}
    					}
    					else{ //if no expression
    						//output blank fields if there's no expression
    						for(int j = 0; j < S_FIELDS; j++){ // S_FIELDS = 4 in this case
    	    					objectFile.append("" + '|'); //ARC flag
    	    					objectFile.append("" + '|' ); //operator + or - or * or / 
    	    					objectFile.append("" + '|'); //sign + / -
    	    					objectFile.append("" + '|'); //external refrence
    						}
    					}
    				}
    				else{ //if NOP
    					//output blank fields if there's no expression
						for(int j = 0; j < S_FIELDS; j++){ // S_FIELDS = 4 in this case
	    					objectFile.append("" + '|'); //ARC flag
	    					objectFile.append("" + '|' ); //operator + or - or * or / 
	    					objectFile.append("" + '|'); //sign + / -
	    					objectFile.append("" + '|'); //external refrence
						}
    				}
    				objectFile.append(modName);
    				objectFile.newLine();
    				count++;
    			}    			
    		}
    		return count;
    	} catch(IOException ioe) {
    		System.out.println("ERROR: Problem writing text record to object file");
    		return -1; //arbitrary error value
    	}
    }
    
    /**
     * Writes the end record for the object file, formatted as defined in Appendix C in the lab manual.
     * 
     * @param objectFile the file this method writes to.
     * @param numberOfRecords the number of records in the object file before this method has written to it.
     * @author Meghan Day
     * 
     * Change Log:<br>
     * 	- 05/07/09 - Meghan Day<br>
     * 		- Filled in method<br>
     * 		- Left catch block blank as currently unsure what to do in the case of an IOException when writing<br><br>
     * 	- 05/08/09 - Meghan Day<br>
     * 		- Filled in catch block<br><br>
     * 	- 05/17/09 - Tobin Chee<br>
     * 		- Deleted newline call because this should be the last line in the file.
     */
    public static void putEndRecord(BufferedWriter objectFile, Integer numberOfRecords){
    	//TODO Meghan
    	//Remember to add 1 to the numberOfRecords when outputting it in the end record because the end record needs to count itself.
    	try {
    		objectFile.write("E|" + Integer.toHexString(numberOfRecords + 1) + "|" + symbolTable.getProgramName());
    		numberOfRecords++;
    	}
    	catch (IOException ioe) {
    		System.out.println("ERROR: Problem writing end record to object file");
    	}
    }
    
    /**
     * Writes the object file using the static and dynamic tables constructed by pass1.<br>
     * Object file is formatted as defined in Appendix C in the lab manual.
     * 
     * @param objectFile the file this method writes to.
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- 05/07/09 - Tobin Chee<br>
     * 		- Added calls to submethods to output the records within the object file.
     */
    public static void putObjectFile(BufferedWriter objectFile){
    	int totalNumberOfRecords = 0;
    	totalNumberOfRecords += putHeaderRecord(objectFile);
    	totalNumberOfRecords += putLinkingRecord(objectFile);
    	totalNumberOfRecords += putTextRecord(objectFile);
    	putEndRecord(objectFile, totalNumberOfRecords);
    }
    
    /**
     * Goes through the intermediateVersion and ensures that symbols used by instructions<br>
     * were all defined somewhere in the program. TODO might need more description, also might<br>
     * need to be responsible for setting the ARC flags for each line of code that consumes memory.
     * 
     * @author Tobin Chee
     * 
     * Change Log:<br>
     * 	- 05/17/09 - Tobin Chee<br>
     * 		- Fixed a bug where AVERT was deleting the wrong symbols
     */
    public static void validateIntermediateVersion(){
    	
    	//Ensure AVERT'ed symbols are defined in the program
    	for(int i = 0; i < symbolTable.length(); i++){
			String symbolLabel = symbolTable.getSymbolLabel(i);
			
    		if(symbolTable.getUsage(i) == SymbolUsage.AVERT){
    			
    			if(symbolTable.getLocation(symbolLabel) == -1){
    				int index = symbolTable.getEQUValue(symbolTable.getSymbolLabel(i));
    				
    				intermediateVersion.addError(index, 57);
    				symbolTable.removeSymbol(symbolTable.getSymbolLabel(i));
    				i--; //indexing adjustment for when a symbol is removed
    			}
    		}
    		//else do nothing
    	}
    	
    	//run thru intermediateVersion and ensure all symbols used were defined, set ARC flags, etc...
    	for(int i = 0; i < intermediateVersion.length(); i++){
    		
    		if(intermediateVersion.getConsumesMemory(i)){
    			
    			if(!(intermediateVersion.getOpCode(i) == machineOps.getHexCode("NOP"))){ //if not a NOP
    				ArithmeticExpression exp = intermediateVersion.getOperandSymbolExpression(i);
    				
    				for(int j = 0; j < exp.length(); j++){
    					String symbolLabel = exp.getSymbolLabel(j);
    					if(symbolLabel.compareTo("") != 0){ //if there is a label
    						
    						if(symbolLabel.compareTo("*") == 0){
    							exp.updateARCFlag(j, 'R');
    						}
    						else if(symbolTable.symbolIsDefined(symbolLabel)){
    							SymbolUsage usage = symbolTable.getUsage(symbolLabel);
    							
    							if((usage == SymbolUsage.DATA_LABEL) || (usage == SymbolUsage.AVERT)){
    								exp.updateARCFlag(j, 'R');
    								exp.updateTermValue(j, symbolTable.getLocation(symbolLabel));
    							}
    							else if(usage == SymbolUsage.EXTRN){
    								exp.updateARCFlag(j, 'C');
    							}
    							else if(usage == SymbolUsage.EQU_VALUE){ //if PRMID, PROGRAM_NAME or EQU
    								//nfe cannot reference a forward EQU symbol
    								intermediateVersion.updateOpCode(i, machineOps.getHexCode("NOP"));
    								intermediateVersion.addError(i, 55);
    							}
    							else{
    								//nfe cannot use symbols defined by the BEGIN or PRMID directive as operands
    								intermediateVersion.updateOpCode(i, machineOps.getHexCode("NOP"));
    								intermediateVersion.addError(i, 56);
    							}
    						}
    						else{
								intermediateVersion.updateOpCode(i, machineOps.getHexCode("NOP"));
								intermediateVersion.addError(i, 54);
    						}
    						
    					}
    					else{ //if expression is empty
    						//TODO No expression = no need to validate, ie do nothing
    					}
    				}
    			}
    			else{ //if NOP
    				//TODO no operation, do not evaluate stuff since NOP takes no operands, ie do nothing
    			}
    		}
    		else{
    			//TODO Consumes no memory, skip, ie do nothing
    		}
    	}
    }

	/**
	 * Uses the information in the static and dynamic tables created in pass one to output a
	 * user report and object file. Calls methods to ensure all labels used are valid and defined, 
	 * and output the user report and object file.
	 * 
	 * @param objectFile file to which the object file is written.
	 * @param reportFile file to which the user report is written.
	 * @param debugFile file to which the debug report is written.
	 * @author Tobin Chee
	 * 
	 * Change Log:<br>
	 * 	- 04/06/09 - Tobin Chee<br>
	 * 		- Created initial skeleton.<br><br>
	 * 	- 05/06/09 - Tobin Chee<br>
	 * 		- Added calls to methods to resolve symbols and output the user report and object file.<br><br>
	 * 	- 05/26/09 - Tobin Chee<br>
	 * 		- Added conditional statement to ensure the object file does not get written if there are fatal errors.<br>
	 * 		- Method still outputs the user report, however, to allow the user to see a better description of what they did wrong.
	 */
	public static void pass2(BufferedWriter objectFile, BufferedWriter reportFile, BufferedWriter debugFile) {
		validateIntermediateVersion();
		//TODO begin debug statements
		putDebugReportToFile(debugFile);
		//TODO end debug statements
		putReportToFile(reportFile);
		if(!intermediateVersion.getContainsFatalError()){ //if theres no fatal errors, then output the object file. We still want the user report to output for fatal errors.
			putObjectFile(objectFile);
		}
	}
}
